Source

HgPreBackup / _HgPreBackup.au3

   1
   2
   3
   4
   5
   6
   7
   8
   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
;****MercurialPreBackup*************************************************
; AutoIt Version: 3.3.8.0
; Language:	English
; Platform:	WinXP
; Author:	Nathan Durnan
; Date:	20111227
; Script Function:
;    Search specified drives or folders for Mercurial Repositories and
;    create clones or update clone contents for any repositories found.
;**********************************************************************
#Region AutoIt3Wrapper;**** AutoIt3Wrapper.exe Directives created/used by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Run_AU3Check=n
#AutoIt3Wrapper_Icon=HgPreBackup.ico
#AutoIt3Wrapper_OutFile=HgPreBackup_x86.exe
#AutoIt3Wrapper_OutFile_Type=exe
#AutoIt3Wrapper_OutFile_X64=HgPreBackup_x64.exe
#AutoIt3Wrapper_Change2CUI=Y
#AutoIt3Wrapper_Compile_both=Y
#AutoIt3Wrapper_UseUpx=y
#AutoIt3Wrapper_Compression=4
#AutoIt3Wrapper_Res_Comment=Automated tool to create/update Mercurial Repository clones for backups.
#AutoIt3Wrapper_Res_Description=Mercurial Repository Pre-Backup Tool
#AutoIt3Wrapper_Res_Fileversion=0.1.1.1
#AutoIt3Wrapper_Res_Field=FileVersion Notes|Beta Test - Purge Orphaned Backups
#AutoIt3Wrapper_Res_Fileversion_AutoIncrement=p
#AutoIt3Wrapper_Res_Language=1033
#AutoIt3Wrapper_Res_LegalCopyright=Open Source
#AutoIt3Wrapper_Res_Compatibility=Vista,Windows7
#AutoIt3Wrapper_Res_SaveSource=y
#AutoIt3Wrapper_Res_Field=Author|Nathan Durnan
#AutoIt3Wrapper_Res_Field=CompileDate|%date%
#AutoIt3Wrapper_Res_Field=CompileScript|AutoIt v3 Script
#AutoIt3Wrapper_Res_Field=CompileVersion|%AutoItVer%
#AutoIt3Wrapper_Res_Field=InternalName|MercurialPreBackup
#AutoIt3Wrapper_Res_Field=OriginalFilename|HgPreBackup.exe
#EndRegion AutoIt3Wrapper;**** AutoIt3Wrapper.exe Directives created/used by AutoIt3Wrapper_GUI ****
;____________________________________________________________
;***** Include Files *****
#Region Inclue Files
#include <Array.au3>
#include <Constants.au3>
#include <Date.au3>
#include <File.au3>
#include <Math.au3>
#include <Timers.au3>
#include "UDFs\GlobalCOM_ErrHandler.au3"	;For dealing with COM errors.
#include "UDFs\GlobalFSO.au3"		;for utilizing a global FileSystemObject.
#include "UDFs\ProcessExitCode.au3"	;for getting exit codes after running processes.
#include "UDFs\SMTP_Mailer.au3"		;for emailing log file.
#EndRegion Inclue Files

;____________________________________________________________
;***** Initialize AutoIt Language Options *****
#Region AutoIt Options
AutoItSetOption("MustDeclareVars", True)
AutoItSetOption("GUIOnEventMode", True)
AutoItSetOption("TrayIconHide", True)
#OnAutoItStartRegister "OnAutoItStart"
OnAutoItExitRegister("OnAutoItExit")
#EndRegion AutoIt Options

;____________________________________________________________
;***** Global Variables & Constants *****
;------------------------------------------------------------
#Region Global Variables and Constants
;***** Define Constants *****
;Generic
Global Const $FO_CREATEDIR =  8;Create directory structure if it doesn't exist (Seems to be missing from FileConstants.au3?)

;Mercurial Commands:
Global Const $HG_FOLDER ='.hg'
Global Const $HG_CMD_CLONE = 'clone'
Global Const $HG_CMD_PULL = 'pull'
Global Const $HG_CMD_UPDATE = 'update'
Global Const $HG_CMD_VERIFY = 'verify'

;NOTE: Mercurial Options ARE CASE SENSITIVE!!!
Global Const $HG_OPT_REPOSITORY = ' -R'		;For repository path specification.
Global Const $HG_OPT_REVISION = ' -r'		;Specify a revision number or name.
Global Const $HG_OPT_CLEAN = ' -C'			;Discard any local changes.
Global Const $HG_OPT_TIME = ' --time'		;Output how long the command takes.
Global Const $HG_OPT_UPDATE = ' -u'			;Update to a revision (will use 'tip' if none specified)
Global Const $HG_OPT_CLONENOUPDATE = ' -U'	;Clone will have an empty working directory.
Global Const $HG_OPT_CLONEPULL = ' --pull'	;Copy all metadata without creating hardlinks.

Global $GS_SETTINGSFILENAME = 'HgPreBackupSettings.ini'	;base name for settings file.
Global $GS_LOGFILENAME = 'HgPreBackup.log'	;base name for log file.

;***** Declare Variables *****
Global $Gs_HgPath			;Path for Mercurial commands.
Global $Gb_HgErr = False
Global $Gs_RepoHomeDir		;Directory location (folder) of repositories to backup.
Global $Gs_BackupDir		;Directory location (folder) where backups are to be made.
Global $Gi_RecurseLimit = 10
Global $Gs_SettingsPath		;Path to retrieve settings file from.
Global $Ga_TimeStampStart	;Timestamp array for application start.
Global $Gf_TimeStart		;Timestamp (in ticks) for application start (floating point value).
Global $Gs_LogFileDir		;Folder (directory) path where to create/write log file.
Global $Gs_LogFilePath		;Full path (w/name) where to create/write log file.
Global $Gh_LogFile 			;Handle for log file
Global $Gi_KeepLogCount		;Number of old logs to keep in log path.
Global $Gi_KeepLogDays		;Days of old logs to keep in log path.
Global $Gb_PurgeBackups		;Purge Orphaned Backups that no longer have a source repository.

Global $Ga_RepoList[1]				;Array containing paths of repositories to be backed up.
Global $Ga_RepoValidErr[1]			;Array containing list of source repositories that failed validation.
Global $Gi_PullCount = 0			;Number of Pull commands issued.
Global $Ga_BackupRepoPullErr[1]		;Array to keep track of any repositories with errors durring Pull
Global $Gi_CloneCount = 0			;Number of Clone commands issued.
Global $Ga_BackupRepoCloneErr[1]	;Array to keep track of any repositories with errors durring Clone
Global $Ga_BackupRepoList[1]		;Array containing paths of repositories in the backup directory.
Global $Ga_BackupRepoValidErr[1]	;Array containing list of backup repositories that failed validation.
Global $Ga_PurgedBackupList[1]		;Array containing list of orphaned backups that have been purged.

;email settings
Global $Gb_ReportErrors		;True = email log if errors encountered.  False = no email.
Global $Gs_SMTPServer		;address for the SMTP server to use.
Global $Gs_SMTPPort			;port used for SMTP server connection.
Global $Gs_SMTPssl			;enables/disables secure socket layer sending (set to 1 if using httpS)
Global $Gs_SMTPUser			;username for the SMTP account
Global $Gs_SMTPPassword		;password for the SMTP account
Global $Gs_MailFromName		;name from whom the email is sent
Global $Gs_MailFromAddress	;address where the mail should be sent from
Global $Gs_MailToAddress	;comma-separated list of destination addresses for the email

#EndRegion Global Variables and Constants

;____________________________________________________________
;***** Local Variables & Constants *****
;------------------------------------------------------------
#Region Local Variables and Constants
;***** Declare Variables *****
Local $iResult, $lError
Local $ii, $jj
Local $sBackupPath
Local $sRelativePath
Local $bFoundMatch

#EndRegion Local Variables and Constants

;____________________________________________________________
;***** Beginning of Main Script *****
;------------------------------------------------------------
#Region - Initialization
;Evaluate CommandLine Params
If ($CmdLine[0] <> 0) Then
	ConsoleWrite("Command Line Param1: " & $CmdLine[1] & @CRLF)
	If FileExists($CmdLine[1]) Then
		$Gs_SettingsPath = $CmdLine[1]
	Else ;no valid file in argument.
		$Gs_SettingsPath = $G_objFSO.BuildPath(@ScriptDir, $GS_SETTINGSFILENAME)
	EndIf ;Check for settings file in arguments.
Else ;no command line parameters
	ConsoleWrite("No Command Line Params" & @CRLF)
	$Gs_SettingsPath = $G_objFSO.BuildPath(@ScriptDir, $GS_SETTINGSFILENAME)
EndIf ;Check command line argument for settings file specification
;Read in settings from file:
_ReadGlobalSettings($Gs_SettingsPath)
;Capture Starting Timestamp
$Gf_TimeStart = _Timer_Init()
$Ga_TimeStampStart = _GetTimeStampArray()
;Create Log File
If ($Gi_KeepLogCount <> 0) And ($Gi_KeepLogDays <> 0) Then
	;Only create log file if keeping it.  If not created, other log functions will still be OK.
	$Gh_LogFile = _LogFileCreate($Gs_LogFileDir, $Gs_LogFilePath, $Ga_TimeStampStart)
	_LogFileAddMessage($Gh_LogFile, "Beginning HgPreBackup Operation")
Endif ;Check if keeping any logs.
#EndRegion - Initialization
;Validate Mercurial Installation or Command Path
If Not _VerifyMercurial() Then
	;Mercurial installation not detected!!!
	;Sorry, can't realy do anything more if can't run Hg commands...
	$Gb_HgErr = True
Else ;Mercurial was successfully detected...
	#Region - Evaluate Source Repositories
	_LogFileAddMessage($Gh_LogFile, "Searching for Repositories at " & $Gs_RepoHomeDir)
	_SearchFolderForRepositories($Gs_RepoHomeDir, $Ga_RepoList, $Ga_RepoValidErr)
	_LogFileAddMessage($Gh_LogFile, "* " & $Ga_RepoList[0] & " Repositories Found *")
	#EndRegion - Evaluate Source Repositories
	ConsoleWrite("========== Backup ==========" & @CRLF)
	_LogFileAddMessage($Gh_LogFile, "Beginning Clone/Pull Operations")
	;Check for backup directory:
	If Not $G_objFSO.FolderExists($Gs_BackupDir) Then
		$G_objFSO.CreateFolder($Gs_BackupDir)
	EndIf ;Check for backup directory.
	;Check source repositories.
	For $ii = 1 To $Ga_RepoList[0]
		$sRelativePath = _PathGetRelative($Gs_RepoHomeDir, $Ga_RepoList[$ii])
		If @error Then ;NOTE: check @error IMMEDIATELY after function call!!!
			$sRelativePath = $G_objFSO.GetBaseName($Ga_RepoList[$ii])
		EndIf ;Check for error geting relative path.
		$sBackupPath = $G_objFSO.BuildPath($Gs_BackupDir, $sRelativePath)
		ConsoleWrite("Backup Path = " & $sBackupPath & @CRLF)
		#Region - Backup Actions
		;Check if source has already been cloned:
		If _CheckFolderForRepository($sBackupPath) Then
			;Backup repository exists - PULL changes from source.
			_LogFileAddMessage($Gh_LogFile, "Pull Changes for " & $Ga_RepoList[$ii])
			$Gi_PullCount += 1 ;increment the count of pulls
			$iResult = _MercurialCommand( _
				$HG_CMD_PULL & $HG_OPT_REPOSITORY, _
				$sBackupPath, _
				' "' & $Ga_RepoList[$ii] & '"' _
				& $HG_OPT_UPDATE)
			If ($iResult = 0) Then ;Error occurred in the Pull command
				$iResult = _ArrayAdd($Ga_BackupRepoPullErr, $sBackupPath)
				If (@error = 0) Then ;NOTE: check @error IMMEDIATELY after function call!!!
					;Successfully added item to the array!
					$Ga_BackupRepoPullErr[0] = $iResult ;update the count in the first array element.
				EndIf ;Check results of adding to the array.
			EndIf ;Check for command error.
			;Update to tip to be sure to catch any subrepository updates.
			_MercurialCommand( _
				$HG_CMD_UPDATE & $HG_OPT_CLEAN & $HG_OPT_REPOSITORY, _
				$sBackupPath, $HG_OPT_REVISION & ' tip')
		Else ;Backup repository does not yet exist.
			;Must CLONE a new backup repository.
			_LogFileAddMessage($Gh_LogFile, "Create Clone of " & $Ga_RepoList[$ii])
			$Gi_CloneCount += 1 ;increment the count of clones
			$iResult = _MercurialCommand( _
				$HG_CMD_CLONE, _
				$Ga_RepoList[$ii], _
				' "' & $sBackupPath & '"' _
				& $HG_OPT_CLONEPULL _
				& $HG_OPT_UPDATE & ' tip')
			If ($iResult = 0) Then ;Error occurred in the Clone command
				$iResult = _ArrayAdd($Ga_BackupRepoCloneErr, $sBackupPath)
				If (@error = 0) Then ;NOTE: check @error IMMEDIATELY after function call!!!
					;Successfully added item to the array!
					$Ga_BackupRepoCloneErr[0] = $iResult ;update the count in the first array element.
				EndIf ;Check results of adding to the array.
			EndIf ;Check for command error.
		EndIf ;Check for existing backup repository.
		;Update back to empty to clean out working directory for cleaner backups
		_MercurialCommand( _
			$HG_CMD_UPDATE & $HG_OPT_CLEAN & $HG_OPT_REPOSITORY, _
			$sBackupPath, $HG_OPT_REVISION & ' 0000')
		#EndRegion - Backup Actions
	Next ;$ii - loop through source repositories.
	#Region - Evaluate Backup Repositories
	ConsoleWrite("========== Post-Backup ==========" & @CRLF)
	_LogFileAddMessage($Gh_LogFile, "Searching for Backup Repositories at " & $Gs_BackupDir)
	_SearchFolderForRepositories($Gs_BackupDir, $Ga_BackupRepoList, $Ga_BackupRepoValidErr)
	;Purge Orphaned Backups (backups that no longer have a source).
	ConsoleWrite("Purge Orphaned Backups..." & @CRLF)
	$ii = 1 ;Initialize Loop Variable
	Do ;Loop through backup repo list.
		$sBackupPath = _PathGetRelative($Gs_BackupDir, $Ga_BackupRepoList[$ii])
		ConsoleWrite(@TAB & "$Ga_BackupRepoList[" & $ii & "] = " & $sBackupPath & @CRLF)
		$bFoundMatch = False ;Initialize flag.
		For $jj = 1 to $Ga_RepoList[0]
			$sRelativePath = _PathGetRelative($Gs_RepoHomeDir, $Ga_RepoList[$jj])
			$iResult = StringCompare($sBackupPath, $sRelativePath)
			If ($iResult = 0) Then
				ConsoleWrite(@TAB & "$Ga_RepoList[" & $jj & "] = " & $sRelativePath & @CRLF)
				$bFoundMatch = True
				ExitLoop ;($jj) ;Found a matching source!
			EndIf ;check for match found.
		Next ;loop through source repositories.
		If Not $bFoundMatch Then
			;Backup not found in Source.
			ConsoleWrite(@TAB & "Backup no longer in Source!" & @CRLF)
			$iResult = _ArrayAdd($Ga_PurgedBackupList, $Ga_BackupRepoList[$ii])
			If ($iResult > 0) Then
				$Ga_PurgedBackupList[0] = $iResult
			EndIf ;Check results of adding item to array.
			If Not $Gb_PurgeBackups Then
				;Just report orphans found.
				_LogFileAddMessage($Gh_LogFile, "Found Orphaned Backup: " & $Ga_BackupRepoList[$ii])
			Else ;Purging Orphaned Backups.
				_LogFileAddMessage($Gh_LogFile, "Purging Orphaned Backup: " & $Ga_BackupRepoList[$ii])
				$iResult = FileRecycle($Ga_BackupRepoList[$ii])
				If ($iResult > 0) Then
					$jj = _ArrayDelete($Ga_BackupRepoList, $ii)
					If ($jj >= 0) Then
						$Ga_BackupRepoList[0] = ($jj - 1) ;don't count the first item - is is placeholder for count only!
						$ii -= 1 ;Jump back one index to make up for removed item on next loop.
					EndIf ;Check for successful array item deletion.
				EndIf ;Check for successful repository deletion.
			EndIf ;Check for PurgeBackups setting.
		EndIf ;Check for backup not found in source.
		$ii += 1 ;Increment Loop Variable.
	Until ($ii > $Ga_BackupRepoList[0]) ;Loop through backup repositories.
	#EndRegion - Evaluate Backup Repositories
EndIf ;Check for valid Mercurial installation.
_LogFileAddMessage($Gh_LogFile, "End of Operations")
_LogFileWriteFooter($Gh_LogFile)
FileClose($Gh_LogFile)
#Region - Error Reporting
;----------------------------------------
;Create error report email if errors detected.
If $Gb_ReportErrors Then
	If $Gb_HgErr _
	Or ($Ga_RepoValidErr[0] > 0) _
	Or ($Ga_BackupRepoCloneErr[0] > 0) _
	Or ($Ga_BackupRepoPullErr[0] > 0) _
	Or ($Ga_BackupRepoValidErr[0] > 0) Then
		;Send an email notifying sysadmin of issues.
		ConsoleWrite("Preparing Error Report Email" & @CRLF)
		Local $sMessageSubject, $sMessageBody
		$sMessageSubject = "Error Report for HgPreBackup on " & @ComputerName
		$sMessageBody = "The HgPreBackup script has encountered a warning or error while backing up repositories on " & @ComputerName & @CRLF & @CRLF
		$sMessageBody &= "Please review the attached log file for further details." & @CRLF
		;Send Message
		$iResult = _INetSmtpMailCom( _
			$Gs_SMTPServer, _
			$Gs_MailFromName, _
			$Gs_MailFromAddress, _
			$Gs_MailToAddress, _
			$sMessageSubject, _
			$sMessageBody, _
			$Gs_LogFilePath, _
			"", "", _
			"Normal", _
			$Gs_SMTPUser, _
			$Gs_SMTPPassword, _
			$Gs_SMTPPort, _
			$Gs_SMTPssl)
		ConsoleWrite("Error Report Email sent.  Return = " & $iResult & @CRLF)
	EndIf ;Check for flagged errors.
EndIf ;check for reporting errors.
#EndRegion - Error Reporting
;Clean Up Log Folder Before Leaving...
_LogFileRemoveOldLogs($Gs_LogFileDir, $Gi_KeepLogCount, $Gi_KeepLogDays)
;Create settings file with validated settings if it doesn't exist.
_CreateSettingsFile($Gs_SettingsPath)

;=End-of-Script========================================================


; =============================================================================
; ==== AutoIt Functions =======================================================
; =============================================================================
#Region AutoIt Functions
; #FUNCTION# ....:	OnAutoItStart *********************************************
; Date Added.....:	20111227
; Author.........:	Nathan Durnan
; Purpose........:	Function called as the script/exe begins
;******************************************************************************
Func OnAutoItStart()
	;MsgBox(0, "OnAutoItStart", "Script Starting...")

EndFunc

; #FUNCTION# ....:	OnAutoItExit **********************************************
; Date Added.....:	20111227
; Author.........:	Nathan Durnan
; Purpose........:	Function called as the script/exe exitis
;******************************************************************************
Func OnAutoItExit()
	;MsgBox(0, "OnAutoItExit", "Script Ending...")
	FileClose($Gh_LogFile)	;Should already happen, but just to be safe...

EndFunc

#EndRegion AutoIt Functions


; =============================================================================
; ==== Support Functions ======================================================
; =============================================================================
#Region Support Functions

; #FUNCTION# ....:	_CreateSettingsFile ***************************************
; Date Added ....:	20120107
; Author ........:	Nathan Durnan
; Description ...:	Create default script settings INI file.
; Remarks .......:	Intended to be called at END of script to pick up validated values.
; Syntax ........:	_CreateSettingsFile($IN_sSettingsFilePath)
; Parameters ....:	$IN_sSettingsFilePath - Path of INI file to create.
; Return values .: N/A
; *****************************************************************************

Func _CreateSettingsFile( _
		$IN_sSettingsFilePath)
	Local $hFile, $myResult

	If FileExists($IN_sSettingsFilePath) Then Return
	$hFile = FileOpen($IN_sSettingsFilePath, ($FO_OVERWRITE + $FO_CREATEDIR))
	ConsoleWrite("FileOpen: hFile, @error: " & $hFile & ', ' & @error & @CRLF)
	$myResult = FileWriteLine($hFile, "; HgPreBackup Settings File")
	$myResult = $myResult And FileWriteLine($hFile, "[paths]")
	$myResult = $myResult And FileWriteLine($hFile, ";----------------------------------------------------------------------")
	$myResult = $myResult And FileWriteLine($hFile, ";This section is where file paths are specified.")
	$myResult = $myResult And FileWriteLine($hFile, ";  hgPath .....: Command path for Mercurial application.")
	$myResult = $myResult And FileWriteLine($hFile, ";                Typically just 'hg' if Mercurial is installed.")
	$myResult = $myResult And FileWriteLine($hFile, ";  RepoPath ...: Path to search for source repositories.")
	$myResult = $myResult And FileWriteLine($hFile, ";  BackupPath .: Path where backup repositories are to be located.")
	$myResult = $myResult And FileWriteLine($hFile, ";  LogPath ....: Path where log files are to be created.")
	$myResult = $myResult And FileWriteLine($hFile, ";                Typically, this is the same as BackupPath.")
	$myResult = $myResult And FileWriteLine($hFile, ";----------------------------------------------------------------------")
	$myResult = $myResult And FileWriteLine($hFile, "hgPath = " & $Gs_HgPath)
	$myResult = $myResult And FileWriteLine($hFile, "repopath = " & $Gs_RepoHomeDir)
	$myResult = $myResult And FileWriteLine($hFile, "backuppath = " & $Gs_BackupDir)
	$myResult = $myResult And FileWriteLine($hFile, "logpath = " & $Gs_BackupDir)
	$myResult = $myResult And FileWriteLine($hFile, ";End of Paths")
	$myResult = $myResult And FileWriteLine($hFile, "[settings]")
	$myResult = $myResult And FileWriteLine($hFile, ";----------------------------------------------------------------------")
	$myResult = $myResult And FileWriteLine($hFile, ";This section is where general preferences are specified.")
	$myResult = $myResult And FileWriteLine($hFile, ";  SubFolderLimt .: Maxmum number of subfolders to check within RepoPath.")
	$myResult = $myResult And FileWriteLine($hFile, ";  Report ..: Send email of log file if errors are encountered.")
	$myResult = $myResult And FileWriteLine($hFile, ";             Expected Values: 'True' or 'False'")
	$myResult = $myResult And FileWriteLine($hFile, ";                 True  -> send email with error report")
	$myResult = $myResult And FileWriteLine($hFile, ";                 False -> no email")
	$myResult = $myResult And FileWriteLine($hFile, ";             NOTE: When True, Email setting MUST be specified!!!")
	$myResult = $myResult And FileWriteLine($hFile, ";  KeepLogCount ..: Keep at least this number of log files. ")
	$myResult = $myResult And FileWriteLine($hFile, ";                   0 will keep no logs (KeepLogDays must also be 0) ")
	$myResult = $myResult And FileWriteLine($hFile, ";                   -1 will keep all logs.")
	$myResult = $myResult And FileWriteLine($hFile, ";  KeepLogDays ...: Keep at least this many days of log files. ")
	$myResult = $myResult And FileWriteLine($hFile, ";                   0 will keep no logs (KeepLogCount must also be 0) ")
	$myResult = $myResult And FileWriteLine($hFile, ";                   -1 will keep all logs.")
	$myResult = $myResult And FileWriteLine($hFile, ";  NOTE - The KeepLog... settings work in combinaton with each other: ")
	$myResult = $myResult And FileWriteLine($hFile, ";       e.g. at least 30 days worth of logs, AND at least 10 logs.")
	$myResult = $myResult And FileWriteLine($hFile, ";       The more generous condition will always take precedence to ")
	$myResult = $myResult And FileWriteLine($hFile, ";       preserve the maximum amount of historical log information.")
	$myResult = $myResult And FileWriteLine($hFile, ";  PurgeBackups ..: Remove backup repositories when they no longer have")
	$myResult = $myResult And FileWriteLine($hFile, ";                   matching source repositories.")
	$myResult = $myResult And FileWriteLine($hFile, ";                   Expected Values: 'True' or 'False'")
	$myResult = $myResult And FileWriteLine($hFile, ";                       True  -> Send orphaned backups to Recycle Bin.")
	$myResult = $myResult And FileWriteLine($hFile, ";                       False -> Leave orphaned backups in BackupPath.")
	$myResult = $myResult And FileWriteLine($hFile, ";----------------------------------------------------------------------")
	$myResult = $myResult And FileWriteLine($hFile, "SubFolderLimit = " & $Gi_RecurseLimit)
	$myResult = $myResult And FileWriteLine($hFile, "Report = " & $Gb_ReportErrors)
	$myResult = $myResult And FileWriteLine($hFile, "KeepLogCount = " & $Gi_KeepLogCount)
	$myResult = $myResult And FileWriteLine($hFile, "KeepLogDays = " & $Gi_KeepLogDays)
	$myResult = $myResult And FileWriteLine($hFile, "PurgeBackups = " & $Gb_PurgeBackups)
	$myResult = $myResult And FileWriteLine($hFile, ";End of Settings")
	$myResult = $myResult And FileWriteLine($hFile, "[email]")
	$myResult = $myResult And FileWriteLine($hFile, ";----------------------------------------------------------------------")
	$myResult = $myResult And FileWriteLine($hFile, ";This section is where email settings are specified.")
	$myResult = $myResult And FileWriteLine($hFile, ";All of the following MUST be specified if Report is True")
	$myResult = $myResult And FileWriteLine($hFile, ";  SMTPServer ....: Name or IP of SMTP server to use. (e.g. smtp.gmail.com)")
	$myResult = $myResult And FileWriteLine($hFile, ";  SMTPPort ......: Port number to use, typically 25 (note: gmail uses 465)")
	$myResult = $myResult And FileWriteLine($hFile, ";  SMTPssl .......: Use Secure Socket Layer protocol or not.")
	$myResult = $myResult And FileWriteLine($hFile, ";                   0 = no ssl, 1 = use ssl (required for gmail)")
	$myResult = $myResult And FileWriteLine($hFile, ";  SMTPUser ......: Username for SMTP login")
	$myResult = $myResult And FileWriteLine($hFile, ";  SMTPPassword ..: Password for SMTP login (IMPORTANT: SEE NOTE BELOW)")
	$myResult = $myResult And FileWriteLine($hFile, ";***********************************************************")
	$myResult = $myResult And FileWriteLine($hFile, ";*!!*  NOTE: This setting is a known security issue!!! ")
	$myResult = $myResult And FileWriteLine($hFile, ";*!!*  Password is stored as plain text, unencryped.  ")
	$myResult = $myResult And FileWriteLine($hFile, ";*!!*  Use at your own risk!!!  Keep this file in a safe location.")
	$myResult = $myResult And FileWriteLine($hFile, ";*************************************************************")
	$myResult = $myResult And FileWriteLine($hFile, ";  FromName ......: Name to identify sender of Email (can be blank)")
	$myResult = $myResult And FileWriteLine($hFile, ";  FromAddress ...: Email address of sender, typical format: name@domain.com")
	$myResult = $myResult And FileWriteLine($hFile, ";  ToAddress .....: Comma separated list of addresses to send message to.")
	$myResult = $myResult And FileWriteLine($hFile, ";----------------------------------------------------------------------")
	$myResult = $myResult And FileWriteLine($hFile, "SMTPServer = " & $Gs_SMTPServer)
	$myResult = $myResult And FileWriteLine($hFile, "SMTPPort = " & $Gs_SMTPPort)
	$myResult = $myResult And FileWriteLine($hFile, "SMTPssl = " & $Gs_SMTPssl)
	$myResult = $myResult And FileWriteLine($hFile, "SMTPUser = " & $Gs_SMTPUser)
	$myResult = $myResult And FileWriteLine($hFile, "SMTPPassword = " & $Gs_SMTPPassword)
	$myResult = $myResult And FileWriteLine($hFile, "FromName = " & $Gs_MailFromName)
	$myResult = $myResult And FileWriteLine($hFile, "FromAddress = " & $Gs_MailFromAddress)
	$myResult = $myResult And FileWriteLine($hFile, "ToAddress = " & $Gs_MailToAddress)
	$myResult = $myResult And FileWriteLine($hFile, ";End of Email ")
	FileClose($hFile)
EndFunc ;==> _CreateSettingsFile

; #FUNCTION# ....:	_ReadGlobalSettings ***************************************
; Date Added ....:	20120104
; Author ........:	Nathan Durnan
; Description ...:	Read script settings from specified INI file.
; Syntax ........:	_ReadGlobalSettings($IN_sSettingsFilePath)
; Parameters ....:	$IN_sSettingsFilePath - Path of INI file to read settings from.
; Return values .: N/A (settings will be filled with default values if any errors occur)
; *****************************************************************************

Func _ReadGlobalSettings( _
		$IN_sSettingsFilePath)
	Local $bValue, $iValue
	#Region Read Path Items:
	Local $sPath, $aTestPath, $szDrive, $szDir, $szFName, $szExt
	;Read in Mercurial Path
	$sPath = IniRead($IN_sSettingsFilePath, 'paths', 'hgpath', "hg.exe")
	;Check for valid Mercurial Path Specification
	$aTestPath = _PathSplit($sPath, $szDrive, $szDir, $szFName, $szExt)
	If ($szFName = '') Then
		$szFName = 'hg'
	EndIf ;check for filename
	If ($szExt = '') Then
		$szExt = 'exe'
	EndIf ;check for extension
	$Gs_HgPath = _PathMake($szDrive, $szDir, $szFName, $szExt)
	;Read in Source Path
	$sPath = IniRead($IN_sSettingsFilePath, 'paths', 'repopath', @ScriptDir)
	;Check for valid Source Path Specification
	$aTestPath = _PathSplit($sPath, $szDrive, $szDir, $szFName, $szExt)
	If ($szDrive = '') Or ($szDir = '') Then
		$szDir = @ScriptDir
	EndIf ;check for drive & directory name
	If ($szExt <> '') Then
		$szFName = ''
	EndIf ;check for extension in path specification.
	$Gs_RepoHomeDir = _PathMake($szDrive, $szDir, $szFName, '')
	;Read in Backup Path
	$sPath = IniRead($IN_sSettingsFilePath, 'paths', 'backuppath', _
			$G_objFSO.BuildPath(@ScriptDir, "HgBackup"))
	;Check for valid Backup Path Specification
	$aTestPath = _PathSplit($sPath, $szDrive, $szDir, $szFName, $szExt)
	If ($szExt <> '') Then
		$szFName = ''
	EndIf ;check for extension in path specification.
	If ($szDrive = '') Or ($szDir = '') Then
		If ($szFName = '') Then
			$szDir = $G_objFSO.BuildPath(@ScriptDir, "HgBackup")
		Else
			$szDir = @ScriptDir
		EndIf ;check for missing file spec.
	EndIf ;check for drive & directory name
	$Gs_BackupDir = _PathMake($szDrive, $szDir, $szFName, '')
	;Read in Log Path
	$sPath = IniRead($IN_sSettingsFilePath, 'paths', 'logpath', $Gs_BackupDir)
	;Check for valid Backup Path Specification
	$aTestPath = _PathSplit($sPath, $szDrive, $szDir, $szFName, $szExt)
	If ($szExt <> '') Then
		$szFName = ''
	EndIf ;check for extension in path specification.
	If ($szDrive = '') Or ($szDir = '') Then
		If ($szFName = '') Then
			$szDir = $G_objFSO.BuildPath(@ScriptDir, "HgBackup")
		Else
			$szDir = @ScriptDir
		EndIf ;check for missing file spec.
	EndIf ;check for drive & directory name
	$Gs_LogFileDir = _PathMake($szDrive, $szDir, $szFName, '')
	#EndRegion Read Path Items
	#Region Read Settings
	$iValue = IniRead($IN_sSettingsFilePath, 'settings', 'SubFolderLimit', 10)
	;Validate Setting Value
	If (IsString($iValue) And _
			StringIsDigit($iValue) Or StringIsFloat($iValue)) _
	Or (IsNumber($iValue)) Then
		$Gi_RecurseLimit = Number($iValue)
	Else ;use default value
		$Gi_RecurseLimit = 10
	EndIf ;check for valid value in setting
	$bValue = IniRead($IN_sSettingsFilePath, 'settings', 'Report', False)
	;Validate Setting Value
	If IsBool ($bValue) Then
		$Gb_ReportErrors = $bValue
	ElseIf IsString($bValue) Or IsNumber($bValue) Then
		Switch $bValue
		Case 't', 'true', 1, -1
			$Gb_ReportErrors = True
		Case Else
			$Gb_ReportErrors = False
		EndSwitch
	Else
		$Gb_ReportErrors = False
	EndIf
	$iValue = IniRead($IN_sSettingsFilePath, 'settings', 'KeepLogCount', -1)
	;Validate Setting Value
	If (IsString($iValue) And _
			StringIsDigit($iValue) Or StringIsFloat($iValue)) _
	Or (IsNumber($iValue)) Then
		$Gi_KeepLogCount = Number($iValue)
	Else ;use default value
		$Gi_KeepLogCount = -1
	EndIf ;check for valid value in setting
	$iValue = IniRead($IN_sSettingsFilePath, 'settings', 'KeepLogDays', -1)
	;Validate Setting Value
	If (IsString($iValue) And _
			StringIsDigit($iValue) Or StringIsFloat($iValue)) _
	Or (IsNumber($iValue)) Then
		$Gi_KeepLogDays = Number($iValue)
	Else ;use default value
		$Gi_KeepLogDays = -1
	EndIf ;check for valid value in setting
	$bValue = IniRead($IN_sSettingsFilePath, 'settings', 'PurgeBackups', False)
	;Validate Setting Value
	If IsBool ($bValue) Then
		$Gb_PurgeBackups = $bValue
	ElseIf IsString($bValue) Or IsNumber($bValue) Then
		Switch $bValue
		Case 't', 'true', 1, -1
			$Gb_PurgeBackups = True
		Case Else
			$Gb_PurgeBackups = False
		EndSwitch
	Else
		$Gb_PurgeBackups = False
	EndIf
	#EndRegion Read Settings
	#Region Read Email Configuration:
	;NOTE: The default settings will probably not work if the IniRead command fails to retrieve data from the file.
	Global $Gs_SMTPServer = IniRead($IN_sSettingsFilePath, 'email', 'SMTPServer', "localhost")
	Global $Gs_SMTPPort = IniRead($IN_sSettingsFilePath, 'email', 'SMTPPort', "25")
	Global $Gs_SMTPssl = IniRead($IN_sSettingsFilePath, 'email', 'SMTPssl', "0")
	Global $Gs_SMTPUser = IniRead($IN_sSettingsFilePath, 'email', 'SMTPUser', @UserName)
	Global $Gs_SMTPPassword = IniRead($IN_sSettingsFilePath, 'email', 'SMTPPassword', "")
	Global $Gs_MailFromName = IniRead($IN_sSettingsFilePath, 'email', 'FromName', @ScriptName)
	Global $Gs_MailFromAddress = IniRead($IN_sSettingsFilePath, 'email', 'FromAddress', @ScriptName & "@localhost")
	Global $Gs_MailToAddress = IniRead($IN_sSettingsFilePath, 'email', 'ToAddress', @UserName & "@localhost")
	#EndRegion Read Email Configuration:
EndFunc ;==> _ReadGlobalSettings


; #FUNCTION# ....:	_CheckFolderForRepository **********************************
; Date Added ....:	20111227
; Author ........:	Nathan Durnan
; Description ...:	Check the specified folder for the existence of a repository.
; Syntax ........:	_CheckFolderForRepository($IN_sFolderPath)
; Parameters ....:	$IN_sFolderPath - Folder path to check.
; Return values .: Success - 1 (Folder contains a repository.)
;                 		@extended = 0 (repository had validation errors.)
;                 		@extended = 1 (repository successfully validated.)
;                  Failure - 0 (Folder does not contain a repository.)
; *****************************************************************************

Func _CheckFolderForRepository( _
		$IN_sFolderPath)
	Local $myReturn, $myResult
	$myReturn = $G_objFSO.FolderExists($G_objFSO.BuildPath($IN_sFolderPath, $HG_FOLDER))
	If $myReturn Then
		ConsoleWrite("Repository Found at " & $IN_sFolderPath & @CRLF)
		;Verify integrity of repository:
		$myResult = _MercurialCommand($HG_CMD_VERIFY & $HG_OPT_REPOSITORY, $IN_sFolderPath, '', True)
	EndIf ;check return value
	Return SetError(0, $myResult, $myReturn)
EndFunc ;==> _CheckFolderForRepository

; #FUNCTION# ....:	_SearchFolderForRepositories ******************************
; Date Added ....:	20111228
; Author ........:	Nathan Durnan
; Description ...:	Search the specified folder for any repositories.
; Syntax ........:	_SearchFolderForRepositories($IN_sFolderPath, $OUT_aRepoPaths)
; Parameters ....:	$IN_sFolderPath - Folder path to check.
;                 	$OUT_aRepoPaths - Array structure to return list of results.
;                 		* Will contain an array of paths to repositories.
;                 		* The first array element will contain the count of items in the array.
;                 	$OUT_aRepoPaths - Array structure to return list of repositories with validation issues.
;                 		* Will contain an array of paths to repositories.
;                 		* The first array element will contain the count of items in the array.
;                 	$optIN_iRecurseLevel - Number of layers of recursion for the current function call.
;                 		* Optional - not required outside of the function itself.
; Return values .: Success - 1 (Folder contains one or more repositories.)
;                  Failure - 0 (Error occurred, or Folder does not contain any repositories.)
;                 		@extended = 1 : Failed to create folder object.
;                 		@extended = 2 : Failed to add path to array.
;                 		@extended = 3 : Folder does not contain repository or subfolders.
;                 		@extended = 4 : Maximum subfolder recursions exceeded.
; Remarks:
;	The assumtion is make that once a repository folder is found, any further
;	recursion into subfolders should be unncessary.  Any subfolders inside a
;	repository should already be part of the repository itself, or be
;	subrepositories that are referenced by the repository and will be cloned
;	or updated with the primary repository.
; *****************************************************************************

Func _SearchFolderForRepositories( _
		$IN_sFolderPath, _
		ByRef $OUT_aRepoPaths, _
		ByRef $OUT_aRepoValidErr, _
		$optIN_iRecurseLevel = 0)
	Local $myReturn = 0, $myError = 0, $myExtended = 0 ;These variables will be used for the function's return statement.
	Local $myobjFolder ;Local Folder object created by the global FileSystemObject.
	Local $myResult ;For evaluating return values of functions called inside this function.

	If ($optIN_iRecurseLevel > $Gi_RecurseLimit) Then
		ConsoleWrite("_SearchFolderForRepositories Recursion = " & $optIN_iRecurseLevel & "!!!" & @CRLF)
		$myExtended = 4
	Else ;Still within recursion limits.
		If $G_objFSO.FolderExists($IN_sFolderPath) Then
			$myobjFolder = $G_objFSO.GetFolder($IN_sFolderPath)
			$myError = @error ;NOTE: check @error IMMEDIATELY after function call!!!
		EndIf ;Check for existing folder.
		If ($myError <> 0) Or Not IsObj($myobjFolder) Then
			;Failed to get folder object...
			$myExtended = 1
		Else ;Folder object successfully created!
			If _CheckFolderForRepository($myobjFolder.Path) Then
				;Check results of repository validation in @extended
				If (@extended = 0) Then ;NOTE: check @extended IMMEDIATELY after function call!!!
					ConsoleWrite("  Error Verifying " & $myobjFolder.Path & @CRLF)
					;Repository had validation errors!
					$myResult = _ArrayAdd($OUT_aRepoValidErr, $myobjFolder.Path)
					If (@error = 0) Then ;NOTE: check @error IMMEDIATELY after function call!!!
						;Successfully added item to the array!
						$OUT_aRepoValidErr[0] = $myResult ;update the count in the first array element.
					EndIf ;Check results of adding to the array.
				EndIf ;Check for repo validation.
				;Folder contains a repository!  Add it to the list...
				$myResult = _ArrayAdd($OUT_aRepoPaths, $myobjFolder.Path)
				$myError = @error ;NOTE: check @error IMMEDIATELY after function call!!!
				If ($myError <> 0) Then
					$myExtended = 2
				Else ;Successfully added item to the array!
					$OUT_aRepoPaths[0] = $myResult ;update the count in the first array element.
					$myReturn = 1
				EndIf ;Check results of adding to the array.
			Else ;Folder is not a repository.
				;Check for sub-folders...
				If ($myobjFolder.SubFolders.Count <= 0) Then
					;No subfolders found...
					ConsoleWrite("Folder " & $myobjFolder.Path & @CRLF)
					ConsoleWrite(@TAB & " has no repository or subfolders!" & @CRLF & @CRLF)
					$myExtended = 3
				ElseIf ($optIN_iRecurseLevel >= $Gi_RecurseLimit) Then
					;Don't recurse through subfolders if already at maximum recursion limit.
					ConsoleWrite("_SearchFolderForRepositories Recursion = " & $optIN_iRecurseLevel & "!!!" & @CRLF)
					$myExtended = 4
				Else ;subfolders exist!
					For $objSubFolder In $myobjFolder.SubFolders
						;**********************************
						;!!!! WARNING - RECURSIVE CALL !!!!
						;----------------------------------
						_SearchFolderForRepositories( _
								$objSubFolder.Path, _
								$OUT_aRepoPaths, _
								$OUT_aRepoValidErr, _
								($optIN_iRecurseLevel + 1))
					Next ;Loop through subfolders.
				EndIf ;Check for subfolders
			EndIf ;Check folder for repository.
		EndIf ;Check for valid folder object.
	EndIf ;Check for maximum recursion limit.
	;Assign Return & Error Values:
	Return SetError($myError, $myExtended, $myReturn)
EndFunc ;==> _SearchFolderForRepositories

#EndRegion Support Functions


; =============================================================================
; ==== Mercurial Functions ====================================================
; =============================================================================
#Region Mercurial Functions

; #FUNCTION# ....:	_VerifyMercurial ******************************************
; Date Added ....:	20111228
; Author ........:	Nathan Durnan
; Description ...:	Check for a working Mercurial installation on the machine.
; Syntax ........:	_VerifyMercurial()
; Parameters ....:	N/A
; Return values .: Success - 1 (A working installtion of Mercurial is detected.)
;                  Failure - 0 (Could not detect Mercurial.)
;                 		@error will contain the error code from attempting to run the "hg" command.
; *****************************************************************************

Func _VerifyMercurial()
	Local $myReturn = 0, $myError = 0, $myExtended = 0 ;These variables will be used for the function's return statement.
	Local $myExitCode

	$myExitCode = RunWait($Gs_HgPath, @ScriptDir, @SW_HIDE)
	$myError = @error ;NOTE: check @error IMMEDIATELY after function call!!!
	ConsoleWrite("'" & $Gs_HgPath & "' ExitCode = " & $myExitCode & @CRLF)
	If ($myError <> 0) Then
		;Failed to run Mercurial command.
		ConsoleWrite("Failed to detect Mercurial!  @error = " & $myError & @CRLF & @CRLF)
		_LogFileAddMessage($Gh_LogFile, "ERROR: Mercurial COULD NOT be Verified!!!!")
		_LogFileAddMessage($Gh_LogFile, "* Mercurial Path = " & $Gs_HgPath)
	Else ;Mercurial command successfully executed!
		_LogFileAddMessage($Gh_LogFile, "Mercurial Successfully Verified")
		$myReturn = 1
	EndIf ;Check results of running Mercurial command.
	;Assign Return & Error Values:
	Return SetError($myError, $myExtended, $myReturn)
EndFunc ;==> _VerifyMercurial

; #FUNCTION# ....:	_MercurialCommand ******************************************
; Date Added ....:	20111228
; Author ........:	Nathan Durnan
; Description ...:	Generic routine used to execute a Mercurial function.
; Syntax ........:	_MercurialCommand($IN_sCommand, $IN_sRepoPath[,$optIN_sOptions[, $optIN_bQuiet]])
; Parameters ....:	$IN_sCommand - Mercurial command to issue.
;                 	$IN_sRepoPath - Path of repository to use for the command.
;                 	$optIN_sOptions - Optional or additional parameters for the command.
;                 	$optIN_bQuiet - Optional flag to suppress console output statements.
; Return values .: Success - 1 ()
;                  Failure - 0 ()
;                 		@exteneded = 1 : Failed to execute command.
;                 			@error will contain the error from attempting to Run the command.
;                 		@exteneded = 2 : Return code was non-zero, indicating an error.
; *****************************************************************************

Func _MercurialCommand( _
		$IN_sCommand, _
		$IN_sRepoPath, _
		$optIN_sOptions = '', _
		$optIN_bQuiet = False)
	Local $myReturn = 0, $myError = 0, $myExtended = 0 ;These variables will be used for the function's return statement.
	Local $sConsoleCommand, $sConsoleOutput = "", $sTemp = ""
	Local $hMyApp, $myHandle, $myExitCode, $myTempError

	$sConsoleCommand = $Gs_HgPath & ' ' & $IN_sCommand & ' "' & $IN_sRepoPath & '"' & $optIN_sOptions & $HG_OPT_TIME
	If Not $optIN_bQuiet Then
		ConsoleWrite($sConsoleCommand & @CRLF)
	EndIf
	_LogFileAddMessage($Gh_LogFile, "  " & $sConsoleCommand)
	$hMyApp = Run($sConsoleCommand, $IN_sRepoPath, @SW_HIDE, $STDERR_MERGED)
	$myError = @error
	If ($myError <> 0) Then
		$myExtended = 1
		If Not $optIN_bQuiet Then
			ConsoleWrite("Error executing command: @error = " & $myError & @CRLF)
		EndIf
		_LogFileAddMessage($Gh_LogFile, "  ERROR Running Command! (@error = " & $myError & ")")
	Else ;Command execution successful!
		$myHandle = _ProcessGetHandle($hMyApp)
		Do ;Read from output stream until nothing more to read.
			$sConsoleOutput &= $sTemp
			$sTemp = StdoutRead($hMyApp)
			$myTempError = @error ;NOTE: check @error IMMEDIATELY after function call!!!
			Sleep(10) ;give the processor a break!
		Until $myTempError ;encountered end of output stream!
		While ProcessExists($hMyApp)
			Sleep(20)
		WEnd ;wait until process closes
		$myExitCode = _ProcessGetExitCode($myHandle)
		_ProcessCloseHandle($myHandle)
		;Evaluate ExitCode...
		Switch $myExitCode
			Case 0 ;Success
				$myReturn = 1
				If Not $optIN_bQuiet Then
					ConsoleWrite(@TAB & "Command OK" & @CRLF)
				EndIf
			Case Else ;Errors encountered
				$myExtended = 2
				If Not $optIN_bQuiet Then
					ConsoleWrite("Errors Encountered: ExitCode = " & $myExitCode & @CRLF)
					ConsoleWrite("---out---" & @CRLF & $sConsoleOutput & @CRLF & "------" & @CRLF)
				EndIf
				_LogFileAddMessage($Gh_LogFile, "    Errors Encountered! (ExitCode = " & $myExitCode & ")")
				;Record console output from command into the log file.
				Local $aOutput, $ii
				$aOutput = StringSplit($sConsoleOutput, @LF, 1)
				For $ii = 1 To $aOutput[0]
					_LogFileAddMessage($Gh_LogFile, "    > " & $aOutput[$ii] )
				Next
				EndSwitch ;check exit code.
	EndIf ;Check for successful command execution.
	;Assign Return & Error Values:
	Return SetError($myError, $myExtended, $myReturn)
EndFunc ;==> _MercurialCommand

#EndRegion Mercurial Functions


; =============================================================================
; ==== Logging/Reporting Functions ============================================
; =============================================================================
#Region Logging/Reporting Functions

; #FUNCTION# ....:	_GetTimeStampArray ******************************************
; Date Added ....:	20120103
; Author ........:	Nathan Durnan
; Description ...:	Get the current time and store it in an array.
; Syntax ........:	_GetTimeStampArray()
; Parameters ....:	N/A
; Return values .: Success - Returns an Array with the following format:
;                 		[0] - Month
;                 		[1] - Day
;                 		[2] - Year
;                 		[3] - Hour
;                 		[4] - Minutes
;                 		[5] - Seconds
;                 		[6] - Milliseconds
;                 		[7] - Day of week
; *****************************************************************************

Func _GetTimeStampArray()
	Local $tTimeCurrent, $aTimeCurrent
	;Capture Current Timestamp Value
	$tTimeCurrent = _Date_Time_GetLocalTime()
	$aTimeCurrent = _Date_Time_SystemTimeToArray($tTimeCurrent)
	Return $aTimeCurrent
EndFunc ;==> _GetTimeStampArray

; #FUNCTION# ....:	_LogFileCreate ******************************************
; Date Added ....:	20120103
; Author ........:	Nathan Durnan
; Description ...:	Create a new log file for recording progress/errors.
; Syntax ........:	_LogFileCreate($IN_sLogFilePath[, $optIN_aTimeStamp])
; Parameters ....:	$IN_sLogFileDir - Folder (directory) path to create the log file at.
;                 	$OUT_sLogFilePath - New filename for created log file.
;                 	$optIN_aTimeStamp - Optional array containing timestamp data.
;                 		Array format is as returned by _GetTimeStampArray() function.
; Return values .: Success - Returns a file "handle" for use with subsequent file functions.
;                  Failure = -1
;                 		@error will contain the error from the FileOpen action.
; *****************************************************************************

Func _LogFileCreate( _
		$IN_sLogFileDir, _
		ByRef $OUT_sLogFilePath, _
		$optIN_aTimeStamp = '')
	Local $sFileName, $sFileExt
	Local $sTimeStamp
	Local $hFile, $iError

	;Capture Current Timestamp Value
	If IsArray($optIN_aTimeStamp) Then
		$sTimeStamp = "_" & StringFormat("%04d%02d%02d-%02d%02d%02d", _
				$optIN_aTimeStamp[2], $optIN_aTimeStamp[0], $optIN_aTimeStamp[1], _
				$optIN_aTimeStamp[3], $optIN_aTimeStamp[4], $optIN_aTimeStamp[5])
	Else ;Timestamp not specified.
		$sTimeStamp = ""
	EndIf ;Check for timestamp array.
	;Create a new filename with timestamp appended.
	$sFileExt = '.' & $G_objFSO.GetExtensionName($GS_LOGFILENAME)
	$sFileName = $G_objFSO.GetBaseName($GS_LOGFILENAME) & $sTimeStamp & $sFileExt
	$OUT_sLogFilePath = $G_objFSO.BuildPath($IN_sLogFileDir, $sFileName)
	;Create new file!
	$hFile = FileOpen($OUT_sLogFilePath, ($FO_OVERWRITE + $FO_CREATEDIR))
	$iError = @error
	If ($hFile > 0) Then
		_LogFileWriteHeader($hFile, $optIN_aTimeStamp)
	EndIf ;Check for valid file handle.
	Return SetError($iError, 0, $hFile)
EndFunc ;==> _LogFileCreate

; #FUNCTION# ....:	_LogFileWriteHeader ******************************************
; Date Added ....:	20120103
; Author ........:	Nathan Durnan
; Description ...:	Write header lines to the log file.
; Syntax ........:	_LogFileWriteHeader($IN_hLogFile[, $optIN_aTimeStamp])
; Parameters ....:	$IN_hLogFile - File handle for Log File (from _LogFileCreate function)
;                 	$optIN_aTimeStamp - Optional array containing timestamp data.
;                 		Array format is as returned by _GetTimeStampArray() function.
; Return values .: Success - 1 ; File written to successfully.
;                  Failure - 0 ; Error writing to file.
;                 		@extended = 0 (file could not be written to)
;                 		@extended = 1 (invalid file handle)
; *****************************************************************************

Func _LogFileWriteHeader( _
		$IN_hLogFile, _
		$optIN_aTimeStamp = '')
	Local $sTimeStamp
	Local $myResult

	If ($IN_hLogFile <= 0) Then Return SetError(1,1,0) ;Can't do anything with an invalid file handle.
	If IsArray($optIN_aTimeStamp) Then
		$sTimeStamp = " Starting " & StringFormat("%04d/%02d/%02d, at %02d:%02d:%02d", _
				$optIN_aTimeStamp[2], $optIN_aTimeStamp[0], $optIN_aTimeStamp[1], _
				$optIN_aTimeStamp[3], $optIN_aTimeStamp[4], $optIN_aTimeStamp[5])
	Else ;Timestamp not specified.
		$sTimeStamp = ""
	EndIf ;Check for timestamp array.
	$myResult = FileWriteLine($IN_hLogFile, "+---------------------------------------------------------------------")
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "|  HgPreBackup Log File" & $sTimeStamp)
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "|  Computer Name  : " & @ComputerName & _
			" (" & @OSVersion & "_" & @OSArch & " " & @OSServicePack & ")")
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "|  User Name      : " & @UserName)
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "+--------+------------+-----------------------------------------------")
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "|  Date  |    Time    | Message     ")
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "+yyyymmdd+hh:mm:ss.mmm+-----------------------------------------------")
	Return $myResult
EndFunc ;==> _LogFileWriteHeader

; #FUNCTION# ....:	_LogFileAddMessage ******************************************
; Date Added ....:	20120103
; Author ........:	Nathan Durnan
; Description ...:	Write a timestamped log message line to the log file.
; Syntax ........:	_LogFileAddMessage($IN_hLogFile, $IN_sMessage)
; Parameters ....:	$IN_hLogFile - File handle for Log File (from _LogFileCreate function)
;                 	$IN_sMessage - Message string to add to log file.
; Return values .: Success - 1 ; File written to successfully.
;                  Failure - 0 ; Error writing to file.
;                 		@extended = 0 (file could not be written to)
;                 		@extended = 1 (invalid file handle)
; *****************************************************************************

Func _LogFileAddMessage( _
		$IN_hLogFile, _
		$IN_sMessage)
	Local $aTimeStamp, $sTimeStamp
	Local $myResult

	If ($IN_hLogFile <= 0) Then Return SetError(1,1,0) ;Can't do anything with an invalid file handle.
	$aTimeStamp = _GetTimeStampArray()
	$sTimeStamp = StringFormat("|%04d%02d%02d|%02d:%02d:%02d.%03d", _
			$aTimeStamp[2], $aTimeStamp[0], $aTimeStamp[1], _
			$aTimeStamp[3], $aTimeStamp[4], $aTimeStamp[5], $aTimeStamp[6])
	$myResult = FileWriteLine($IN_hLogFile, $sTimeStamp & "| " & $IN_sMessage)
	Return $myResult
EndFunc ;==> _LogFileAddMessage

; #FUNCTION# ....:	_LogFileWriteFooter ******************************************
; Date Added ....:	20120104
; Author ........:	Nathan Durnan
; Description ...:	Write footer lines to the log file.
; Syntax ........:	_LogFileWriteFooter($IN_hLogFile)
; Parameters ....:	$IN_hLogFile - File handle for Log File (from _LogFileCreate function)
; Return values .: Success - 1 ; File written to successfully.
;                  Failure - 0 ; Error writing to file.
;                 		@extended = 0 (file could not be written to)
;                 		@extended = 1 (invalid file handle)
; *****************************************************************************

Func _LogFileWriteFooter( _
		$IN_hLogFile)
	Local $myResult, $ii

	If ($IN_hLogFile <= 0) Then Return SetError(1,1,0) ;Can't do anything with an invalid file handle.
	$myResult = FileWriteLine($IN_hLogFile, "+--------+------------+-----------------------------------------------")
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "+---------------------------------------------------------------------")
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "| ~~ SUMMARY ~~ " )
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "| AutoIt Verion......: " & @AutoItVersion)
	If @Compiled Then
		$myResult = $myResult And FileWriteLine($IN_hLogFile, "| Script Verion......: " & FileGetVersion(@ScriptFullPath))
	Else ;running from script - no version number
		$myResult = $myResult And FileWriteLine($IN_hLogFile, "| Script Verion......: (not compiled)" )
	EndIf ;check for compiled script
	If Not $Gb_HgErr Then
		$myResult = $myResult And FileWriteLine($IN_hLogFile, "| Mercurial Verion...: " & FileGetVersion($Gs_HgPath))
	Else ;error detected with Mercurial
		$myResult = $myResult And FileWriteLine($IN_hLogFile, "| Mercurial Verion...: (could not verify Mercurial!)")
	EndIf ;check for Mercurial error
	Local $fTimerElapsed = _Timer_Diff($Gf_TimeStart)/1000
	If ($fTimerElapsed > 90) Then
		Local $fSeconds = Mod($fTimerElapsed, 60)
		Local $iMinutes = Floor(($fTimerElapsed - $fSeconds) / 60)
		$myResult = $myResult And FileWriteLine($IN_hLogFile, "| Elapsed Time.......: " & _
				$iMinutes & " minutes, " & StringFormat('%.3f',$fSeconds) & " seconds")
	Else ;time is small enough to express in just seconds.
		$myResult = $myResult And FileWriteLine($IN_hLogFile, "| Elapsed Time.......: " & _
				StringFormat('%.3f',$fTimerElapsed) & " seconds")
	EndIf ;check elapsed time magnitude.
	;__________________
	;==== SETTINGS ====
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "| ________")
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "| SETTINGS")
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Settings Path..: " & $Gs_SettingsPath)
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Mercurial Path.: " & $Gs_HgPath)
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Source Path....: " & $Gs_RepoHomeDir)
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Backup Path....: " & $Gs_BackupDir)
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Log File Path..: " & $Gs_LogFilePath)
	If Not $Gb_HgErr Then
		;_____________________________
		;==== SOURCE REPOSITORIES ====
		$myResult = $myResult And FileWriteLine($IN_hLogFile, "| ___________________")
		$myResult = $myResult And FileWriteLine($IN_hLogFile, "| SOURCE REPOSITORIES")
		$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Total Found.........: " & $Ga_RepoList[0])
		If ($Ga_RepoList[0] <= 0) Then ;check for any repositories found.
			$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Total Found.........: none (huh?)")
		Else ;At least one repository was found.
			$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Total Found.........: " & $Ga_RepoList[0])
			If ($Ga_RepoValidErr[0] > 0) Then
				$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Validation Errors...: " & $Ga_RepoValidErr[0])
				$myResult = $myResult And FileWriteLine($IN_hLogFile, "|       Review the following repositories:")
				For $ii = 1 To $Ga_RepoValidErr[0]
					$myResult = $myResult And FileWriteLine($IN_hLogFile, "|       > " & $Ga_RepoValidErr[$ii])
				Next ;loop through list of repos
			Else ;No Validation Errors
				$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Validation Errors...: none (yaay!)")
			EndIf ;Check for Validation Errors
		EndIf ;check for any repositories found.
		;_____________________________
		;==== BACKUP REPOSITORIES ====
		$myResult = $myResult And FileWriteLine($IN_hLogFile, "| ___________________")
		$myResult = $myResult And FileWriteLine($IN_hLogFile, "| BACKUP REPOSITORIES")
		$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Total Created (Cloned)..: " & $Gi_CloneCount)
		If ($Ga_BackupRepoCloneErr[0] > 0) Then
			$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Clone Errors...: " & $Ga_BackupRepoCloneErr[0])
			$myResult = $myResult And FileWriteLine($IN_hLogFile, "|       Review the following repositories:")
			For $ii = 1 To $Ga_BackupRepoCloneErr[0]
				$myResult = $myResult And FileWriteLine($IN_hLogFile, "|       > " & $Ga_BackupRepoCloneErr[$ii])
			Next ;loop through list of repos
		EndIf ;Check for Clone Errors
		$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Total Synch'd (Pulled)..: " & $Gi_PullCount)
		If ($Ga_BackupRepoPullErr[0] > 0) Then
			$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Pull Errors...: " & $Ga_BackupRepoPullErr[0])
			$myResult = $myResult And FileWriteLine($IN_hLogFile, "|       Review the following repositories:")
			For $ii = 1 To $Ga_BackupRepoPullErr[0]
				$myResult = $myResult And FileWriteLine($IN_hLogFile, "|       > " & $Ga_BackupRepoPullErr[$ii])
			Next ;loop through list of repos
		EndIf ;Check for Pull Errors
		If ($Ga_BackupRepoList[0] <= 0) Then ;check for any repositories found.
			$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Total Found.............: none (huh?)")
		Else ;At least one repository was found.
			$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Total Found.............: " & $Ga_BackupRepoList[0])
			If ($Ga_BackupRepoValidErr[0] > 0) Then
				$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Validation Errors.......: " & $Ga_BackupRepoValidErr[0])
				$myResult = $myResult And FileWriteLine($IN_hLogFile, "|       Review the following repositories:")
				For $ii = 1 To $Ga_BackupRepoValidErr[0]
					$myResult = $myResult And FileWriteLine($IN_hLogFile, "|       > " & $Ga_BackupRepoValidErr[$ii])
				Next ;loop through list of repos
			Else ;No Validation Errors
				$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Validation Errors.......: none (yaay!)")
			EndIf ;Check for Validation Errors
		EndIf ;check for any repositories found.
		If ($Ga_PurgedBackupList[0] > 0) Then
			$myResult = $myResult And FileWriteLine($IN_hLogFile, "|     Orphaned Backups Found..: " & $Ga_PurgedBackupList[0])
			If Not $Gb_PurgeBackups Then
				$myResult = $myResult And FileWriteLine($IN_hLogFile, "|       The following no longer have matching source repositories")
				$myResult = $myResult And FileWriteLine($IN_hLogFile, "|       and should be evaluated as to their usefulness: ")
			Else ;Orphans have been deleted.
				$myResult = $myResult And FileWriteLine($IN_hLogFile, "|       The following no longer have matching source repositories")
				$myResult = $myResult And FileWriteLine($IN_hLogFile, "|       and have been moved to the Recycle Bin: ")
			EndIf ;Check for PurgeBackups setting.
			For $ii = 1 to $Ga_PurgedBackupList[0]
					$myResult = $myResult And FileWriteLine($IN_hLogFile, "|       > " & $Ga_PurgedBackupList[$ii])
			Next ;Loop through list of repos
		EndIf ;Check for any purged orphans.
	Endif ;Check for mercurial installation/path errors.
	$myResult = $myResult And FileWriteLine($IN_hLogFile, "+---------------------------------------------------------------------")
	Return $myResult
EndFunc ;==> _LogFileWriteFooter

; #FUNCTION# ....:	_LogFileRemoveOldLogs *************************************
; Date Added ....:	20120105
; Author ........:	Nathan Durnan
; Description ...:	Remove old log files, leaving a specified number of logs in the directory.
; Remarks........:	Log files are removed to the Recycle Bin, not permanently deleted.
;	The number of log files to be left in the directory depends on both the
;		number of files and the number of days worth of files to keep.
;		The more generous parameter takes priority.
;	For example, assume 10 logs per day for 5 days for a total of 50 files.
;	If this function is told to keep 10 files and 4 days of logs,
;		it will leave 40 log files in the folder.
;	If it is told to keep 1 day of logs and 25 files,
;		it will leave 25 files in the folder.
;	If either parameter is negative, ALL files will always be kept.
;	In order to delete all logs, both parameters must be set to zero (0).
; Syntax ........:	_LogFileRemoveOldLogs($IN_sLogFileDir, $IN_iKeepLogs, $IN_iKeepDays)
; Parameters ....:	(2) inputs required
;	$IN_sLogFileDir		;Folder Path (directory) where log files reside.
;	$IN_iKeepLogs		;Number of log files to leave in folder.
;							-1 = Keep ALL logs (no files will be removed)
;							 0 = Remove ALL logs (ALL log files will be deleted)
;							1+ = Keep the specified number (older files will be removed)
;	$IN_iKeepDays		;Number of days of files to leave in folder.
;						NOTE: a "day" is considered the 24-hour period prior to this function being called.
;							-1 = Keep ALL logs (no files will be removed)
;							 0 = Remove ALL logs (ALL log files will be deleted)
;							1+ = Keep the specified number of days (older files will be removed)
; Return values .: N/A
; *****************************************************************************

Func _LogFileRemoveOldLogs( _
		$IN_sLogFileDir, _
		$IN_iKeepLogs, _
		$IN_iKeepDays)
	Local $aFileList, $aFileData, $aFileTime, $iFileAge
	Local $myError
	If Not FileExists($IN_sLogFileDir) Then Return SetError(0, 1, 0);Can't clean a folder that doesn't exist!
	If ($IN_iKeepLogs < 0) And ($IN_iKeepDays < 0) Then Return SetError(0, 1, 0);Negative value means keep everything, so nothing to do.

	$aFileList = _FileListToArray($IN_sLogFileDir , _
			$G_objFSO.GetBaseName($GS_LOGFILENAME) & '*.' & _
			$G_objFSO.GetExtensionName($GS_LOGFILENAME), _
			1)
	$myError = @error
	If Not IsArray($aFileList) Then Return SetError($myError, 2, 0);Couldn't file any files, so nothing more to do.
	;Resize Data array to match file list.
	Dim $aFileData[$aFileList[0]+1][2]
	$aFileData[0][0] = $aFileList[0]
	For $ii = 1 To $aFileList[0]
		$aFileData[$ii][0] = $aFileList[$ii]
		;Evaluate CREATED time, not modified or accessed.
		$aFileTime = FileGetTime( _
						$G_objFSO.BuildPath( _
								$IN_sLogFileDir, _
								$aFileData[$ii][0]), _
						$FT_CREATED, 0)
		$aFileData[$ii][1] = StringFormat("%04d/%02d/%02d %02d:%02d:%02d", _
				$aFileTime[0], $aFileTime[1], $aFileTime[2], _
				$aFileTime[3], $aFileTime[4], $aFileTime[5])
	Next ;loop through file list.
	_ArraySort($aFileData, 1, 1, '', 1)
	;Get Current Timestamp
	Local $aTimeStamp, $sTimeStamp
	$aTimeStamp = _GetTimeStampArray()
	$sTimeStamp = StringFormat("%04d/%02d/%02d %02d:%02d:%02d", _
			$aTimeStamp[2], $aTimeStamp[0], $aTimeStamp[1], _
			$aTimeStamp[3], $aTimeStamp[4], $aTimeStamp[5])
	;Check List of Files against count and day quotas
	Local $iStartDelete = 1 + _Min($IN_iKeepLogs, $aFileData[0][0])
	For $ii = $iStartDelete To $aFileData[0][0]
		$iFileAge = (_DateDiff('h', $aFileData[$ii][1], $sTimeStamp) / 24)
		$myError = @error
		If ($iFileAge > $IN_iKeepDays) Then
			ConsoleWrite("Sending Expired Log File to Recycle Bin: " & $aFileData[$ii][0] & @CRLF)
			FileRecycle($G_objFSO.BuildPath($IN_sLogFileDir, $aFileData[$ii][0]))
		EndIf ;Check for expired files.
	Next ;loop through remaining list.
EndFunc ;==> _LogFileRemoveOldLogs

#EndRegion Logging/Reporting Functions



;EOF
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.