Commits

Nathan Durnan committed 0cc80ed Merge

Merge with Release 0.2.6
- Adds International Character (mbcs) support.
- Ensures timestamps are only saved for files in the commit set.
- Better checking for existing ".hgtimestamp" file.
- Fixed handling of JSON timestamp file for an empty Working Directory.

Comments (0)

Files changed (6)

 "FileData":{
 ".hgignore": {"timestamp": 1336516662.38},
 ".hgtags": {"timestamp": 1339691777.77},
-"README.md": {"timestamp": 1339691478.75},
+"README.md": {"timestamp": 1342031813.02},
+"Tests/BBI36_CheckTimestampFileExists_Test.bat": {"timestamp": 1342032060.52},
+"Tests/BBI37_SaveOnlyCommittedTimestamps_Test.bat": {"timestamp": 1342032121.8},
+"Tests/BBI38_EmptyUpdate_Test.bat": {"timestamp": 1341604677.09},
 "TimeStampMod.png": {"timestamp": 1305052883.0},
-"TimestampMod.py": {"timestamp": 1339691056.98},
+"TimestampMod.py": {"timestamp": 1342194746.52},
 "TimeStampMod.xmind": {"timestamp": 1306451621.66},
 "TimestampMod_LastRecord": {"timestamp": 0}
 }
 TimestampMod
 ============
-About (version 0.2.4 beta)
+About (version 0.2.6 beta)
 --------------------------
 TimestampMod is an extension for Mercurial DVCS that incorporates automatic saving and restoring of the modification times of files under version control.  This extension is based on an original timestamp extension by [Friedrich Kastner-Masilko](mailto:face@snoopie.at) hosted at [https://bitbucket.org/face/timestamp][ts].
 
 --------------
 These release notes will not cover every version, just tip of the repository and previous major release points.
 
-### __0.2.5 (beta)__ - _June 14, 2012_
+### __0.2.6 (beta)__ - _July 11, 2012_
 This is a bug-fix release.  
 **ALL USERS OF v0.2.x ARE URGED TO UPDATE TO THIS VERSION!**
 
 + __Changed__ - Features or functionality modified with this version:
-    * The extension will abort running the Post-Merge and Post-Resolve hooks until there are no unresolved files.  Command line merge tools can leave extra lines in unresolved files to help with manual merging.  This makes it impossible for the extension to read the JSON timestamp file.  Since unresolved files indicate an intermediate merge state, reapplying the timestamps to the unresolved state would likely be incorrect in the first place.
+    * The extension will abort running the Post-Merge and Post-Resolve hooks until there are no unresolved files.  Command line merge tools can leave extra lines in unresolved files to help with manual merging.  This makes it impossible for the extension to read the JSON timestamp file.  Since unresolved files indicate an intermediate merge state, reapplying the timestamps to the unresolved state would likely be incorrect in the first place.  
     _(changed in TimestampMod v0.2.3)_
+    * The extension will no longer report a missing timestamp record file (.hgtimestamp) as an error when creating a new repository.  The error message was misleading - the missing file really is a low-priority condition.  The extension now quietly deals with the missing file without creating panic for the user.  
+    _(changed in TimestampMod v0.2.6)_
 + __Fixed__ - Issues fixed with this version:
     * A compatibility issue with the command line Mercurial package was fixed.  The Python library distributed with the command line Mercurial package does not include the JSON module!  A separate Python installation is required for use with the command line Mercurial package.  The extension can now reference an external Python library to pick up the components it needs that may be missing from Mercurial or TortoiseHg native Python libraries.  
     _(fixed in TimestampMod v0.2.3)_
     _(fixed in TimestampMod v0.2.4)_
     * Exception error occurred when using TimestampMod with older versions of MQ patch queue extension.  The MQ 'qrefresh' was calling commit with match.files() as set() instead of list().  The TimestampMod extension now coerces the match.files() object to a list to avoid this issue.  
     _(fixed in TimestampMod v0.2.5)_
+    * Save Timestamp for Committed Files ONLY.  When committing specific files, the extension was saving the timestamps of ALL files tracked in the repository even if they are not included in the commit. It should only be saving timestamps for files that have been included in the commit.  
+    _(fixed in TimestampMod v0.2.6)_
+    * Error occurred when trying to update to a revision that had no files in the Working Directory.  The extension did not find any timestamp records in the JSON file, so it was attempting to open it as a CSV file.  It now recognizes the lack of timestamp records as an emtpy Working Directory.  
+    _(fixed in TimestampMod v0.2.6)_
+    * Filenames with international characters in them (Japanese CP932 for example) were not supported.  Reading the timestamp file as JSON would fail and attempt to read it as CSV (and still fail).  
+    _(fixed in TimestampMod v0.2.6)_
 
 ### __0.2.2 (beta)__ - _April 26, 2012_
 This is a feature change beta release.  The format of the timestamp file (.hgtimestamp) has changed with this release in order to be more forward-compatible.  

Tests/BBI36_CheckTimestampFileExists_Test.bat

+::------------------------------------------------------------------------------
+:: Tests for BitBucket Issue #36 - Quiet Check for Existing Timestamp File.
+:: The message "*** Error accessing .hgtimestamp file! ***" is too strong.
+:: The file will be recreated if it is missing.  No message needed.
+::------------------------------------------------------------------------------
+:: This test-script creates a temporary test repository,
+:: creates and addes a single file, and commits the file.
+::------------------------------------------------------------------------------
+@echo off
+echo.
+echo ===========================================
+echo Test #1 - New Repository - Commit Normally.
+echo.
+echo ----------
+echo Initializing Test Repository...
+if exist testrepo rmdir /S /Q testrepo
+mkdir testrepo
+cd testrepo
+hg init
+echo Create file (abc.txt)
+echo "abc" > abc.txt
+hg add abc.txt
+echo hg commit -m "abc"
+hg commit -m "abc"
+echo --------------------------------------------
+echo CHECK: no error message should be displayed.
+echo ============================================
+pause
+echo.
+echo.
+echo =============================================
+echo Test #2 - New Repository - Commit w/ --debug.
+echo.
+echo ----------
+echo Initializing Test Repository...
+if exist testrepo rmdir /S /Q testrepo
+mkdir testrepo
+cd testrepo
+hg init
+echo Create file (abc.txt)
+echo "abc" > abc.txt
+hg add abc.txt
+echo hg commit -m "abc" --debug
+hg commit -m "abc" --debug
+echo --------------------------------------------
+echo CHECK: no error message should be displayed,
+echo        just a simple notification message.
+echo ============================================
+pause

Tests/BBI37_SaveOnlyCommittedTimestamps_Test.bat

+::------------------------------------------------------------------------------
+:: Tests for BitBucket Issue #37 - Save Timestamp for Committed Files ONLY.
+:: When committing specific files, the extension is saving the timestamps of ALL
+:: files tracked in the repository even if they are not included in the commit.
+:: It should only be saving timestamps for files included in the commit.
+::------------------------------------------------------------------------------
+:: This test-script creates a temporary test repository and adds two files to it.
+:: * The first test will modify both files and commit only one of them.
+::    - Only the timestamp for the committed file should be changed.
+:: * The second test will modify both files and commit without specifying a file.
+::    - The timestamps for both of the files should be changed.
+::------------------------------------------------------------------------------
+@echo off
+echo Initializing Test Repository...
+if exist testrepo rmdir /S /Q testrepo
+mkdir testrepo
+cd testrepo
+hg init
+echo Create first file (abc.txt)
+echo "abc" > abc.txt
+hg add abc.txt
+hg commit -m "abc"
+echo Create second file (bcd.txt)
+echo "abc" > bcd.txt
+hg add bcd.txt
+hg commit -m "add bcd"
+echo.
+echo ============================================
+echo Test #1: Modify both files, commit only one.
+echo.
+echo ----------
+echo Timestamps before changes
+type .hgtimestamp
+echo "abc" >> abc.txt
+echo "efg" >> bcd.txt
+echo.
+echo.
+echo hg commit -m "commit bcd only" bcd.txt
+hg commit -m "commit bcd only" bcd.txt
+echo.
+echo ----------
+echo Timestamps after committing only bcd.txt
+type .hgtimestamp
+echo.
+echo ------------------------------------------------------
+echo CHECK: ONLY the bcd.txt timestamp should have changed.
+echo ======================================================
+pause
+echo.
+echo.
+echo ==============================================
+echo Test #2: Modify both files, commit everything.
+echo.
+echo ----------
+echo Timestamps before commit
+type .hgtimestamp
+echo "123" >> abc.txt
+echo "456" >> bcd.txt
+echo.
+echo.
+echo hg commit -m "commit all (no match)"
+hg commit -m "commit all (no match)"
+echo.
+echo ----------
+echo Timestamps after committing with no Match
+type .hgtimestamp
+echo.
+echo -------------------------------------------
+echo CHECK: BOTH timestamps should have changed.
+echo ===========================================
+pause

Tests/BBI38_EmptyUpdate_Test.bat

+::------------------------------------------------------------------------------
+:: Tests for BitBucket Issue #38 - Read JSON File with no Timestamp data.
+:: The _read_TimestampJSONRecords function fails and returns an error when 
+:: updating to a revision that has no timestamp data recorded.
+::------------------------------------------------------------------------------
+:: This test-script creates a temporary test repository,
+:: creates and addes a single file, and commits the file.
+:: The file is then removed and the removal is committed.
+:: Finally, the Working directory is updated to both revisions.
+::------------------------------------------------------------------------------
+@echo off
+echo.
+echo Initializing Test Repository...
+if exist testrepo rmdir /S /Q testrepo
+mkdir testrepo
+cd testrepo
+hg init
+echo Create file (abc.txt)
+echo "abc" > abc.txt
+hg add abc.txt
+echo hg commit -m "add abc.txt"
+hg commit -m "add abc.txt"
+echo hg remove abc.txt
+hg remove abc.txt
+echo hg commit -m "remove abc.txt"
+hg commit -m "remove abc.txt"
+echo.
+echo =============================================
+echo Test #1 - Update to Rev-0 and Rev-1 normally.
+echo.
+echo ----------
+echo hg update 0
+hg update 0
+echo.
+echo.
+echo hg update 1
+hg update 1
+echo.
+echo ----------------------------------------------
+echo CHECK: no error messages should be displayed. 
+echo It should not try to open .hgtimestamp as CSV.
+echo ==============================================
+pause
+echo.
+echo.
+echo ===============================================
+echo Test #2 - Update to Rev-0 and Rev-1 w/ --debug.
+echo.
+echo ----------
+echo hg update 0 --debug
+hg update 0 --debug
+echo.
+echo.
+echo hg update 1 --debug
+hg update 1 --debug
+echo.
+echo ---------------------------------------------
+echo CHECK: no error messages should be displayed.
+echo It should not try to open .hgtimestamp as CSV.
+echo =============================================
+pause
 # begin Extension Help Text:
 '''Automatically store and retrieve file modification times.'''
 # end help text
-#==============================================================================
-# TimestampMod.py - Automatically save and restore the modification times of files
-File_Version = '0.2.5'	# Version number definition
+#=============================================================================
+# TimestampMod.py - Automatically save and restore file modification times 
+File_Version = '0.2.6'  # Version number definition
 # --> !!BETA RELEASE!!! <--
 # Copyright 2011-2012 Nathan Durnan <nedmech@gmail.com>
 #
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
-#------------------------------------------------------------------------------
+#-----------------------------------------------------------------------------
 # Summary: This is an extension written for Mercurial/TortoiseHG that allows
 #	the original modification times of files under version control to be
 #	recorded and restored during commit, update, revert, etc. operations.
 #
 # Development information:
-#	Mercurial Version:	1.8.3 - 2.2.2 (from TortoiseHg package)
-#	Python Version:		2.6.6 (from TortoiseHg package)
+#	Mercurial Version:  1.8.3 - 2.2.2 (from TortoiseHg package)
+#	Python Version:     2.6.6 (from TortoiseHg package)
 #	TortoiseHg Version: 2.0.4 - 2.4.1
-#==============================================================================
+#=============================================================================
 
-#==============================================================================
+#=============================================================================
 # Import Modules
-#------------------------------------------------------------------------------
+#-----------------------------------------------------------------------------
 import sys	#requied for debugging/exception info.
 import os	#required for filesystem access methods.
 import os.path	#required for filesystem path methods.
 import json	#use JSON format for storing timestamp data in file.
 import inspect	#required for getting path/name of current code module.
 import fnmatch	#required for checking file patterns.
-from mercurial import localrepo	#required for creating a pseudo-pre-commit hook.
+from mercurial import localrepo	#required for creating pseudo-pre-commit hook.
 from mercurial import match as matchmod	#required for "match" object in commit wrapper.
 from mercurial import merge as mergemod	#required for merge state (check unresolved)
 from mercurial import cmdutil	#required for working with "Revert" command methods.
 from mercurial import commands	#required for working with "Revert" command methods.
-#_ end of imported modules_____________________________________________________
+#_ end of imported modules____________________________________________________
 
-#==============================================================================
+#=============================================================================
 # Global Objects
-#------------------------------------------------------------------------------
+#-----------------------------------------------------------------------------
 File_TimestampRecords = '.hgtimestamp'
 LastPlaceholder = 'TimestampMod_LastRecord'
 TimeStamp_dict = dict()
-#_ end of global objects ______________________________________________________
+#_ end of global objects _____________________________________________________
 
 
 
-#==============================================================================
+#=============================================================================
 # uisetup Callback Configuration
-#------------------------------------------------------------------------------
+#-----------------------------------------------------------------------------
 # NOTES: Called when the extension is first loaded and receives a ui object.  
-#	This is the FIRST callback that is executed when intializing this extension.
-#==============================================================================
+#	This is the FIRST callback executed when intializing this extension.
+#=============================================================================
 def uisetup(ui):
 	'''Initialize UI-Level Callback'''
 	ui.debug('* Loading TimestampMod uisetup\n')
 	ui.setconfig("hooks", "post-merge.TimestampMod", Hook_Post_Merge)
 	ui.setconfig("hooks", "post-resolve.TimestampMod", Hook_Post_Resolve)
 	ui.setconfig("hooks", "post-revert.TimestampMod", Hook_Post_Revert)
-#_ end of uisetup _____________________________________________________________
+#_ end of uisetup ____________________________________________________________
 
 
-#==============================================================================
+#=============================================================================
 # extsetup Callback Configuration
-#------------------------------------------------------------------------------
+#-----------------------------------------------------------------------------
 # NOTES: Called after all the extension have been initially loaded.
-#	This is the SECOND callback that is executed when intializing this extension.
+#	This is the SECOND callback executed when intializing this extension.
 #	It can be used to access other extensions that this one may depend on.
-#==============================================================================
+#=============================================================================
 def extsetup(ui):
 	'''Initialize Extension-Level Callback'''
 	ui.debug('* Loading TimestampMod extsetup\n')
 	pass
-#_ end of extsetup ____________________________________________________________
+#_ end of extsetup ___________________________________________________________
 
 
-#==============================================================================
+#=============================================================================
 # reposetup Callback Configuration
-#------------------------------------------------------------------------------
+#-----------------------------------------------------------------------------
 # NOTES: Called after the main Mercurial repository initialization.
-#	This is the LAST callback that is executed when intializing this extension.
+#	This is the LAST callback executed when intializing this extension.
 #	It can be used to setup any local state the extension might need.
-#==============================================================================
+#=============================================================================
 def reposetup(ui, repo):
 	'''Initialize Repository-Level Callback'''
 	ui.debug('* Loading TimestampMod reposetup\n')
 		extension.wrapcommand() methods failed to work with the version
 		of TortoiseHg used for development.  Ideally, this will be 
 		revised to a cleaner method in the future.'''
-		localrepo.localrepository.timestamp_origcommit = localrepo.localrepository.commit
+		localrepo.localrepository.timestamp_origcommit = \
+			localrepo.localrepository.commit
 		localrepo.localrepository.commit = Wrap_Commit
-#_ end of reposetup ___________________________________________________________
+#_ end of reposetup __________________________________________________________
 
 
-#==============================================================================
+#=============================================================================
 # Wrap_Commit Function Definition
-#------------------------------------------------------------------------------
+#-----------------------------------------------------------------------------
 # Summary: Intercept the commit event to update the timestamp record file, and
 #	make sure the record file gets included in the commit.
 # NOTES: This is a "dirty" method of wrapping the commit event so pre-commit 
-#	actions are executed.  Normal pre-commit hooks and extensions.wrapcommand()
-#	 methods failed to work with the version of TortoiseHg used for development .  
+#	actions are executed. Normal pre-commit hooks and extensions.wrapcommand()
+#	 methods failed to work with the TortoiseHg version used for development.  
 #	Ideally, this will be revised to a cleaner method in the future.
-#==============================================================================
-def Wrap_Commit(repo, text="", user=None, date=None, match=None, force=False, editor=False, extra={}):
+#=============================================================================
+def Wrap_Commit(
+		repo, 
+		text="", 
+		user=None, 
+		date=None, 
+		match=None, 
+		force=False, 
+		editor=False, 
+		extra={}):
 	repo.ui.note('TimestampMod|Wrap_Commit accessed!\n')
 	#Check for a merge-commit. 
 	#  Don't run timestamp code until merge is complete.
 	if (len(repo.parents()) > 1):
-		repo.ui.status('TimestampMod|Wrap_Commit aborted - Merge in progress\n')
+		repo.ui.status(
+			'TimestampMod|Wrap_Commit aborted', 
+			' - Merge in progress\n'
+			)
 	else:
 		# Make sure the match object is created.
 		if not match:
 			repo.ui.debug('Empty match: Must create!\n')
-			match = matchmod.always(repo.root, '') #create an empty match object
+			#create an empty match object
+			match = matchmod.always(repo.root, '')
 		else:
 			pass
 		# End of check for non-existent match object.
 			#coerce files() to a list object.
 			match._files = list(match.files())
 		#end of check for list type
-		myList_Match = match.files() #don't add timestamp file here, it will be added later.
-		timestamp_mod(repo.ui, repo, **dict({'save': True, 'restore': None, 'match': myList_Match}))
+		myList_Match = match.files() 
+		#don't add timestamp file here, it will be added later.
+		timestamp_mod(
+			repo.ui, 
+			repo, 
+			**dict({
+				'save': True, 
+				'restore': None, 
+				'match': myList_Match
+				})
+			)
 		# Make sure record file is part of repository and commit. 
 		if not (File_TimestampRecords in repo.dirstate):
-			repo.ui.debug('Wrap_Commit: ', File_TimestampRecords, ' not in repo.dirstate  Adding...\n')
-			repo[None].add([File_TimestampRecords]) #same method used for adding '.hgtags' file in localrepo.py
+			repo.ui.debug(
+				'Wrap_Commit: ', 
+				File_TimestampRecords, 
+				' not in repo.dirstate  Adding...\n'
+				)
+			#\/ same method used for adding '.hgtags' file in localrepo.py
+			repo[None].add([File_TimestampRecords]) 
 		#end of check for record file in repository.
 		#Update match fileset for use under TortoiseHg.
 		#  TortoiseHg doesn't seem to catch the updated file
 		#  unless it is manually added to the match fileset.
 		if (File_TimestampRecords in match.files()):
 			# Don't need to do anything if record file already in commit.
-			repo.ui.debug('Wrap_Commit: ', File_TimestampRecords, ' already in match\n')
+			repo.ui.debug(
+				'Wrap_Commit: ', 
+				File_TimestampRecords, 
+				' already in match\n'
+				)
 			pass
 		else:
 			# Add the record file to the match object.
 		repo.ui.debug('Match Files: ', str(match.files()), '\n')
 	#end of check for merge-commit.
 	repo.ui.note('TimestampMod|Wrap_Commit finished!\n')
-	return repo.timestamp_origcommit(text, user, date, match, force, editor, extra)
-#_ end of Wrap_Commit _________________________________________________________
+	return repo.timestamp_origcommit(
+			text, 
+			user, 
+			date, 
+			match, 
+			force, 
+			editor, 
+			extra
+			)
+#_ end of Wrap_Commit ________________________________________________________
 
 
-#==============================================================================
+#=============================================================================
 # Hook Function Definitions
-#------------------------------------------------------------------------------
+#-----------------------------------------------------------------------------
 # Summary: These functions are intended to be triggered by the hooks defined
 #	either by Mercurial or in the configuration files.
 # NOTES: The pre-** hooks are the only ones that does not function properly
 #	under the TortoiseHg GUI.  All the hooks work from command-line.
-#==============================================================================
+#=============================================================================
 # Hook_Pre_Commit is depreciated in favor of Wrap_Commit method
 #	(Wrap_Commit works with both native Mercurial and TortoiseHg.)
 '''def Hook_Pre_Commit(repo, **kwargs):
 	repo.ui.note('TimestampMod|Post-Status Hook accessed!\n')
 	myUnresolved = _check_Merge_unresolved(repo)
 	if myUnresolved:
-		repo.ui.note('TimestampMod|Post-Status Hook aborted - Unresolved merge detected!\n')
+		repo.ui.note(
+			'TimestampMod|Post-Status Hook aborted', 
+			' - Unresolved merge detected!\n'
+			)
 		return
 	#end check for unresolved merged
-	timestamp_mod(repo.ui, repo, **dict({'save': None, 'restore': None}))
+	timestamp_mod(
+		repo.ui, 
+		repo, 
+		**dict({
+			'save': None, 
+			'restore': None
+			})
+		)
 
 def Hook_Update(repo, **kwargs):
 	repo.ui.note('TimestampMod|Hook_Update accessed!\n')
 	if (len(repo.parents()) > 1):
-		repo.ui.note('TimestampMod|Hook_Update aborted - Merge in progress\n')
+		repo.ui.note(
+			'TimestampMod|Hook_Update aborted', 
+			'- Merge in progress\n'
+			)
 	else:
-		timestamp_mod(repo.ui, repo, **dict({'save': None, 'restore': True}))
+		timestamp_mod(
+			repo.ui, 
+			repo, 
+			**dict({
+				'save': None, 
+				'restore': True
+				})
+			)
 	#end of check for merging.
 
 def Hook_Post_Merge(repo, **kwargs):
 	repo.ui.note('TimestampMod|Post-Merge Hook accessed!\n')
-	#repo.ui.debug('Post-Merge:kwargs = \n', str(kwargs), '\n')
 	myUnresolved = _check_Merge_unresolved(repo)
 	if myUnresolved:
-		repo.ui.note('TimestampMod|Post-Merge Hook aborted - Unresolved merge detected!\n')
+		repo.ui.note(
+			'TimestampMod|Post-Merge Hook aborted', 
+			' - Unresolved merge detected!\n'
+			)
 		return
 	#end check for unresolved merged
 	myPreview = False #starting value
 	#end of check for 'opts' keyword.
 	if (not myPreview):
 		#only update timestamps if not just a preview.
-		timestamp_mod(repo.ui, repo, **dict({'save': None, 'restore': True}))
+		timestamp_mod(
+			repo.ui, 
+			repo, 
+			**dict({
+				'save': None, 
+				'restore': True
+				})
+			)
 	#check for preview option.
 
 def Hook_Post_Resolve(repo, **kwargs):
 	repo.ui.note('TimestampMod|Post-Resolve Hook accessed!\n')
-	#repo.ui.debug('Post-Resolve:kwargs = \n', str(kwargs), '\n')
 	myUnresolved = _check_Merge_unresolved(repo)
 	if myUnresolved:
-		repo.ui.note('TimestampMod|Post-Resolve Hook aborted - Unresolved merge detected!\n')
+		repo.ui.note(
+			'TimestampMod|Post-Resolve Hook aborted', 
+			' - Unresolved merge detected!\n'
+			)
 		return
 	#end check for unresolved merged
 	myResolveAll = False #starting value
 		#end of check for 'all' option.
 	#end of check for 'opts' keyword.
 	if (myResolveAll or (File_TimestampRecords in str(kwargs['pats']))):
-		#Only re-apply timestamps if the timestamp file is the one being resolved.
-		repo.ui.status("Resolved timestamp file - Reapplying timestamps!\n")
-		timestamp_mod(repo.ui, repo, **dict({'save': None, 'restore': True}))
+		#Only re-apply timestamps if the timestamp file is being resolved.
+		repo.ui.status('Resolved timestamp file - Reapplying timestamps!\n')
+		timestamp_mod(
+			repo.ui, 
+			repo, 
+			**dict({
+				'save': None, 
+				'restore': True
+				})
+			)
 	#end of check for timestamp file resolve.
 
 def Hook_Post_Revert(repo, **kwargs):
 	is on their list of items that need fixed:
 	https://bitbucket.org/tortoisehg/thg/issue/1347/add-support-for-pre-and-post-hooks
 	'''
-	repo.ui.note("TimestampMod|Post-Revert Hook accessed!\n")
-	#repo.ui.debug("-----\nPost-Revert:kwargs = \n", str(kwargs), "\n-----\n")
+	repo.ui.note('TimestampMod|Post-Revert Hook accessed!\n')
 	bDryRun = False #starting value
 	bAll = False #starting value
 	listExclude = list()
 			#Don't bother to check for rev-spec. 
 			# Original command would've failed and not 
 			# gotten here if both date and rev were spec'd.
-			kwargs['opts']['rev'] = cmdutil.finddate(repo.ui, repo, kwargs['opts']['date'])
+			kwargs['opts']['rev'] = \
+				cmdutil.finddate(
+					repo.ui, 
+					repo, 
+					kwargs['opts']['date']
+					)
 		#end of check for date specified.
 	#end of check for 'opts' keyword.
 	#Establish lists of potentially reverted files from repository status.
-	modified, added, removed, deleted, unknown, ignored, clean = repo.status(node2=kwargs['opts']['rev'])
+	modified, added, removed, deleted, unknown, ignored, clean = \
+		repo.status(node2=kwargs['opts']['rev'])
 	maybeReverted = modified + added
 	#Create a temporary copy of the timestamp file from the source revision.
-	commands.cat(repo.ui, repo, 
-		File_TimestampRecords, File_TimestampRecords, 
-		**dict({'rev':kwargs['opts']['rev'], 'output':'%s.revert'}))
+	commands.cat(
+		repo.ui, 
+		repo, 
+		File_TimestampRecords, 
+		File_TimestampRecords, 
+		**dict({
+			'rev':kwargs['opts']['rev'], 
+			'output':'%s.revert'
+			})
+		)
 	#Create dictionary entries for items that were reverted.
 	if bAll:
 		_get_RepoFileList(repo, list(), TimeStamp_dict)
 			if os.path.isfile(myFileName):
 				TimeStamp_dict[myFileName] = -1
 			elif os.path.isdir(myFileName):
-				#Check the potential list of reverted files against the directory path pattern.
+				#Check the potential list of reverted files 
+				# against the directory path pattern.
 				for sFile in sorted(maybeReverted):
 					if fnmatch.fnmatch(sFile, (myFileName + '/*')):
 						TimeStamp_dict[sFile] = -1
 		#end of loop through pattern list
 	#end of check for 'all' flag
 	# Retrieve existing timestamps from the record file.
-	myErr = _read_TimestampJSONRecords(repo, (File_TimestampRecords + '.revert'), TimeStamp_dict)
+	myErr = _read_TimestampJSONRecords(
+				repo, 
+				(File_TimestampRecords + '.revert'), 
+				TimeStamp_dict
+				)
 	if (not bDryRun):
 		if not myErr:
 			_restore_Timestamps(repo, TimeStamp_dict)
 	try:
 		os.unlink(repo.wjoin(File_TimestampRecords + '.revert'))
 	except:
-		repo.ui.status("Post-Revert: error deleting temporary timestamp file!\n")
+		repo.ui.status(
+			'Post-Revert: ', 
+			'error deleting temporary timestamp file!\n'
+			)
 	#end of deleting temporary timestamp file.
-#_ end of Hook Functions ______________________________________________________
+#_ end of Hook Functions _____________________________________________________
 
 
-#==============================================================================
+#=============================================================================
 # timestamp_mod 
-#------------------------------------------------------------------------------
+#-----------------------------------------------------------------------------
 # Summary: save or restore file modification times.
 #
-#==============================================================================
+#=============================================================================
 def timestamp_mod(ui, repo, **kwargs):
 	'''Save or restore file modification times.'''
-	ui.note("Executing timestamp_mod function\n")
+	ui.note('Executing timestamp_mod function\n')
 	# Retrieve Repository file list contents.
 	myChangedList = list()
 	myDroppedList = list()
 	myMatchList = list()
 	if ('match' in kwargs):
-		ui.debug("-----\nmatch: ", str(kwargs['match']), "\n")
+		ui.debug('-----\nmatch: ', str(kwargs['match']), '\n')
 		myMatchList = kwargs['match']
 	else:
-		ui.debug("-----\nmatch argument not specified\n")
+		ui.debug('-----\nmatch argument not specified\n')
 	# end of check for match argument'''
 	# Build initial file lists from the repository contents.
-	myChangedList, myDroppedList = _get_RepoFileList(repo, myMatchList, TimeStamp_dict)
+	myChangedList, myDroppedList = \
+		_get_RepoFileList(repo, myMatchList, TimeStamp_dict)
 	# Retrieve existing timestamps from the record file.
-	myErr = _read_TimestampJSONRecords(repo, File_TimestampRecords, TimeStamp_dict)
-	
+	myErr = _read_TimestampJSONRecords(
+				repo, 
+				File_TimestampRecords, 
+				TimeStamp_dict
+				)
 	# Check for command optional argument
 	if kwargs['save']:
-		_save_TimestampsJSON(repo, File_TimestampRecords, myChangedList, myDroppedList, TimeStamp_dict)
-	elif not myErr:	# Only evaluate Restore or Display if file was read.
+		_save_TimestampsJSON(
+				repo, 
+				File_TimestampRecords, 
+				myMatchList, 
+				myChangedList, 
+				myDroppedList, 
+				TimeStamp_dict
+				)
+	elif not myErr: 
+		# Only evaluate Restore or Display if file was read.
 		if kwargs['restore']:
 			_restore_Timestamps(repo, TimeStamp_dict)
 		else:
 			_display_Timestamps(repo, TimeStamp_dict)
 		# end of check options (Restore/Display)
 	else:
-		repo.ui.debug('Timestamp_Mod can not continue without ', File_TimestampRecords, ' file! \n')
+		repo.ui.debug(
+			'Timestamp_Mod can not continue without ', 
+			File_TimestampRecords, ' file! \n'
+			)
 	# end of check options
-#_ end of timestamp_mod _______________________________________________________
+#_ end of timestamp_mod ______________________________________________________
 
 
-#==============================================================================
+#=============================================================================
 # Command Table Definition
-#------------------------------------------------------------------------------
+#-----------------------------------------------------------------------------
 # (NOTE: Keep this after command definitions.  cmdtable contents 
 #		 must be defined after the commands/functions referenced!)
-#==============================================================================
+#=============================================================================
 cmdtable = {
 	"timestamp_mod":
 		(timestamp_mod, 
 				'\n  ' + '(Version ' + File_Version + ')')
 		) #end of timestamp_mod
 }
-#_ end of cmdtable ____________________________________________________________
+#_ end of cmdtable ___________________________________________________________
 
 
-
-#==============================================================================
+#=============================================================================
 # _get_fileModTime() Function Definition
-#------------------------------------------------------------------------------
-# Summary: Return a UTC timestamp value for the specified file's modified time.
-#==============================================================================
+#-----------------------------------------------------------------------------
+# Summary: Return UTC timestamp value for the specified file's modified time.
+#=============================================================================
 def _get_fileModTime(repo, IN_FileName):
 	'''Retrieve the Modification Timestamp for the specified file.'''
 	repo.ui.debug('get_mtime: ')
 	myFilePath = repo.wjoin(IN_FileName)
 	try:
 		myModTime = float(os.stat(myFilePath).st_mtime)
-		repo.ui.debug(time.strftime("%Y.%m.%d %H:%M:%S", time.localtime(myModTime)), " \t", IN_FileName, "\n")
+		repo.ui.debug(
+			time.strftime( 
+				'%Y.%m.%d %H:%M:%S', 
+				time.localtime(myModTime)
+				), 
+			' \t', IN_FileName, '\n'
+			)
 		return myModTime
 	except:
-		repo.ui.warn('*** TimestampMod: Get File Stat failed for ', IN_FileName, '!\n')
+		repo.ui.warn(
+			'*** TimestampMod: Get File Stat failed for ', 
+			IN_FileName, '!\n'
+			)
 		repo.ui.debug('*** Exception: ', str(sys.exc_info()), '  ***\n')
 		return -1
 	# end of file stat access.
-#_ end of _get_fileModTime ____________________________________________________
+#_ end of _get_fileModTime ___________________________________________________
 
 
-
-#==============================================================================
+#=============================================================================
 # _set_fileModTime() Function Definition
-#------------------------------------------------------------------------------
+#-----------------------------------------------------------------------------
 # Summary: Set the UTC timestamp value for the specified file's modified time.
-#==============================================================================
-def _set_fileModTime(repo, IN_FileName, IN_ModTime):
+#=============================================================================
+def _set_fileModTime(
+		repo, 
+		IN_FileName, 
+		IN_ModTime 
+		):
 	'''Assign the Modification Timestamp for the specified file.'''
 	repo.ui.debug('set_mtime: ')
 	myFilePath = repo.wjoin(IN_FileName)
 	try:
 		myFileStat = os.stat(myFilePath)
-		os.utime(myFilePath, (myFileStat.st_atime, type(myFileStat.st_mtime)(IN_ModTime)))
-		repo.ui.debug(time.strftime("%Y.%m.%d %H:%M:%S", time.localtime(IN_ModTime)), " \t", IN_FileName, "\n")
+		os.utime(
+			myFilePath, 
+			(myFileStat.st_atime, 
+				type(myFileStat.st_mtime)(IN_ModTime)
+				)
+			)
+		repo.ui.debug(
+			time.strftime('%Y.%m.%d %H:%M:%S', 
+				time.localtime(IN_ModTime)
+				), 
+			' \t', IN_FileName, '\n'
+			)
 	except:
-		repo.ui.warn('*** TimestampMod: Set File Stat failed for ', IN_FileName, '! ***\n')
+		repo.ui.warn(
+			'*** TimestampMod: Set File Stat failed for ', 
+			IN_FileName, '! ***\n'
+			)
 		repo.ui.debug('*** Exception: ', str(sys.exc_info()), '  ***\n')
 	# end of file stat access.
-#_ end of _set_fileModTime ____________________________________________________
+#_ end of _set_fileModTime ___________________________________________________
 
 
-
-#==============================================================================
+#=============================================================================
 # _get_RepoFileList Function Definition
-#------------------------------------------------------------------------------
-# Summary: Build lists of the files in the Working Directory from the Repository
+#-----------------------------------------------------------------------------
+# Summary: Build lists of files in the Working Directory from the Repository
 #	Status entries.  Add active files (clean/added/modified) to the global 
 #	dictionary collection, andreturn lists containing changed files (added/
 #	modified) and dropped files(removed/deleted).  
-# NOTE: This function will CLEAR the contents of the global dictionary collection
+# NOTE: This function will CLEAR the contents of the global dictionary object
 #	and rebuild it from scratch.
-#==============================================================================
-def _get_RepoFileList(repo, IN_ListMatch, OUT_TimeStamp_dict):
+#=============================================================================
+def _get_RepoFileList(
+		repo, 
+		IN_ListMatch, 
+		OUT_TimeStamp_dict
+		):
 	'''Build lists of files from the repository status contents.'''
-	repo.ui.debug('______\nGenerating file list from repo...\n------\n')
+	repo.ui.debug(
+		'______\n', 
+		'Generating file list from repo...\n', 
+		'------\n'
+		)
 	# Establish category lists from repository status.
-	modified, added, removed, deleted, unknown, ignored, clean = repo.status(ignored=True, clean=True, unknown=True)
-	myChanged = IN_ListMatch + modified + added
+	modified, added, removed, deleted, unknown, ignored, clean = \
+		repo.status(ignored=True, clean=True, unknown=True)
+	# Changed files include modifications and additions.
+	# Leave the match list out of the changed list contents.
+	myChanged = modified + added
 	myDropped = removed + deleted
-	myFiles = myChanged + clean
+	# Be sure to include in the match list in the files to review.
+	myFiles = IN_ListMatch + myChanged + clean
 	# Rebuild global dictionary collection
-	OUT_TimeStamp_dict.clear() # Be sure to start with a clean collection.
+	# Be sure to start with a clean collection.
+	OUT_TimeStamp_dict.clear() 
 	for myFile in myFiles:
 		if myFile not in myDropped:
-			#Only add non-dropped files to the list, even if they are part of the match list.
+			#Only add non-dropped files to the list, 
+			# even if they are part of the match list.
 			myFileName = str(myFile).strip()
-			OUT_TimeStamp_dict[myFileName] = -1	# initialize dictionary entry
+			# initialize dictionary entry
+			OUT_TimeStamp_dict[myFileName] = -1
 			repo.ui.debug('Tracking:  ', myFileName, '\n')
 		# end of check for droppped files.
 	# end of loop through repo files.
 	myReturnList = myChanged, myDropped
 	return myReturnList
-#_ end of _get_RepoFileList ___________________________________________________
+#_ end of _get_RepoFileList __________________________________________________
 
 
-
-#==============================================================================
+#=============================================================================
 # _read_TimestampRecords Function Definition
-#------------------------------------------------------------------------------
+#-----------------------------------------------------------------------------
 # Summary: Read in the data from the Timestamp Record File and assign the 
 #	timestamps to their corresponding entries in the global file dictionary
 #	collection object.
 # NOTES:
-# * This method is to be kept in tact in order to be able to deal with the
-#   original CSV timestamp file format that may have been recorded and commited
-#   using previous versions of this extension.  DO NOT LOSE this functionality!
-#==============================================================================
-def _read_TimestampRecords(repo, IN_TimestampFileName, INOUT_TimeStamp_dict):
+# * This method is to be kept in tact to deal with the original 
+#   CSV timestamp file format that may have been commited using 
+#   previous versions of this extension.  DO NOT LOSE this functionality!
+#=============================================================================
+def _read_TimestampRecords(
+		repo, 
+		IN_TimestampFileName, 
+		INOUT_TimeStamp_dict
+		):
 	'''Read data from Timestamp Record File.'''
 	myTimeStampRecordsFile = ''
 	try:
 		myTimeStampRecordsFile = open(repo.wjoin(IN_TimestampFileName), 'r')
-		repo.ui.debug('______\nRetrieving timestamps from record file:\n------\n')
-		for myLine in myTimeStampRecordsFile.readlines():
-			# Read the data from the line. (CSV format: [FileName],[ModificationTime])
-			try:
-				myFileName, myModTime = myLine.strip().split(',')
-				#Only import data for entries already in local dictionary.
-				if myFileName in INOUT_TimeStamp_dict:
-					#Make sure incoming data is properly formatted.
-					INOUT_TimeStamp_dict[str(myFileName)] = float(myModTime)
-					repo.ui.debug('UTC: ', myModTime, '\t: ', myFileName, '\n')
-				# end of check file exists in dictionary.
-			except:
-				repo.ui.debug('Invalid data on line: ', myLine)
-			# end of read data from line.
-		# end of readlines from record file.
-		myTimeStampRecordsFile.close()
-		return False 	# no return flag as successful.
 	except:
-		repo.ui.warn('*** Error accessing ', IN_TimestampFileName, ' file! ***\n')
+		repo.ui.warn(
+			'*** Error accessing ', 
+			IN_TimestampFileName, 
+			' file! ***\n'
+			)
 		repo.ui.debug('*** Exception: ', str(sys.exc_info()), '  ***\n')
 		return True	# set return flag on error.
-	# end of accessing record file.
-#_ end of _read_TimestampRecords ______________________________________________
+	# end of opening record file.
+	repo.ui.debug(
+		'______\n', 
+		'Retrieving timestamps from record file:\n', 
+		'------\n'
+		)
+	for myLine in myTimeStampRecordsFile.readlines():
+		# Read the data from the line. 
+		# (CSV format: [FileName],[ModificationTime])
+		try:
+			myFileName, myModTime = myLine.strip().split(',')
+			#Only import data for entries already in local dictionary.
+			if myFileName in INOUT_TimeStamp_dict:
+				#Make sure incoming data is properly formatted.
+				INOUT_TimeStamp_dict[str(myFileName)] = float(myModTime)
+				repo.ui.debug(
+					'UTC: ', myModTime, 
+					'\t: ', myFileName, '\n'
+					)
+			# end of check file exists in dictionary.
+		except:
+			repo.ui.debug('Invalid data on line: ', myLine)
+		# end of read data from line.
+	# end of readlines from record file.
+	myTimeStampRecordsFile.close()
+	return False 	# no return flag as successful.
+#_ end of _read_TimestampRecords _____________________________________________
 
 
-
-#==============================================================================
+#=============================================================================
 # _read_TimestampJSONRecords Function Definition
-#------------------------------------------------------------------------------
-# Summary: Read in the data from the Timestamp JSON Record File and assign the 
+#-----------------------------------------------------------------------------
+# Summary: Read in the data from the Timestamp JSON Record File and assign the
 #	timestamps to their corresponding entries in the global file dictionary
 #	collection object.
 # NOTES:
 # * This method will fall back to use the previous CSV file read method if it
 #   can not read the file as JSON data.
-#==============================================================================
-def _read_TimestampJSONRecords(repo, IN_TimestampFileName, INOUT_TimeStamp_dict):
+# * Many thanks to BitBucket user TAKAHIRO Kitahara (flied_onion) 
+#   (https://bitbucket.org/flied_onion) for huge contributions with 
+#   implementing and testing correct encoding for international support.
+#=============================================================================
+def _read_TimestampJSONRecords(
+		repo, 
+		IN_TimestampFileName, 
+		INOUT_TimeStamp_dict
+		):
 	'''Read data from Timestamp JSON Record File.'''
 	myTimeStampJSONFile = ''
 	myErr = False #initialize as boolean
+	if not os.path.exists(repo.wjoin(IN_TimestampFileName)):
+		# No file to read from, so just return and treat it as an error.
+		# If saving, a new file will be created.
+		# If restoring, nothing more can be done without the file data.
+		return True
+	# end of check for existing file
+	# Open timestamp record file.
 	try:
-		myTimeStampJSONFile = open(repo.wjoin(IN_TimestampFileName), 'r')
-		repo.ui.debug('______\nRetrieving timestamps from JSON record file:\n------\n')
-		try:
-			myData = json.load(myTimeStampJSONFile)
-			# Check for version and object data:
-			if ('FileData' in myData):
-				if (LastPlaceholder in myData['FileData']):
-					#Don't import placeholder into local dictionary.
-					del myData['FileData'][LastPlaceholder]
-				myWarnCount = 0 #initialize counter.
-				for s_fileName, obj_fileData in myData['FileData'].items():
-					#Only import data for entries already in local dictionary.
-					if s_fileName in INOUT_TimeStamp_dict:
-						myWarn = False #initialize warning flag for each item.
-						#Make sure incoming data is properly formatted.
-						if isinstance(obj_fileData, float):
-							# Keep this section for compatibility 
-							# with v0.2.1 timestamp file.
-							f_fileModTime = float(obj_fileData)
-							#myErr = False 	# no return flag as successful.
-						elif isinstance(obj_fileData, dict):
-							# As of v0.2.2, file data is stored within
-							# a dict object for future extensibility.
-							if ('timestamp' in obj_fileData):
-								f_fileModTime = float(obj_fileData['timestamp'])
-								#myErr = False 	# no return flag as successful.
-							else: # Error - missing timestamp entry in dictionary.
-								f_fileModTime = -1 # use explicitly invalid value if none found.
-								myWarn = True
-								repo.ui.warn('WARNING: Missing timestamp definition for ', 
-									str(s_fileName), ': ', str(obj_fileData), '\n')
-						else: # Error - not a recognized data type.
-							f_fileModTime = -1 # use explicitly invalid value if none found.
-							myWarn = True
-							repo.ui.warn('WARNING: Undefined data for ', 
-								str(s_fileName), ': ', str(type(obj_fileData)), ' = [', str(obj_fileData), ']\n')
-						# end of check for data type
-						if not myWarn:
-							INOUT_TimeStamp_dict[str(s_fileName)] = f_fileModTime
-							repo.ui.debug('UTC: ', str(f_fileModTime), '\t: ', str(s_fileName), '\n')
-						else:
-							myWarnCount += 1 # increment count of problem reads.
-						# end of check for per-item warning.
-					# end of check file exists in dictionary.
-				# end of loop through items.
-				if (myWarnCount >= len(myData['FileData'])):
-					repo.ui.debug('ERROR: Could not read any JSON file data from ', IN_TimestampFileName, '\n')
-					myErr = True	# Error - could not find JSON data
-				# end of check warning count.
-			else: # JSON file data is not present
-				repo.ui.debug(IN_TimestampFileName, ' does not have JSON file data.\n')
-				myErr = True	# Error - could not find JSON data
-			# end of check for file data.
-		except: # report errors
-			repo.ui.debug('Error loading JSON file\n')
-			repo.ui.debug('*** Exception: ', str(sys.exc_info()), '  ***\n')
-			myErr = True	# Error - problem loading JSON file.
-		finally: #cleanup clause
-			myTimeStampJSONFile.close()
-			if myErr: #error return detected - try older version.
-				# Try opening as a pre-v0.2.0 CSV file insted:
-				repo.ui.warn('Opening ', IN_TimestampFileName, ' as CSV file\n')
-				myErr = _read_TimestampRecords(repo, IN_TimestampFileName, INOUT_TimeStamp_dict)
-		# end of reading record file.
-		return myErr
+		myTimeStampJSONFile = open(repo.wjoin(IN_TimestampFileName), 'rb')
 	except: #report errors
-		repo.ui.warn('*** Error accessing ', IN_TimestampFileName, ' file! ***\n')
+		repo.ui.warn(
+			'*** Error opening ', 
+			IN_TimestampFileName, 
+			' file! ***\n'
+			)
 		repo.ui.debug('*** Exception: ', str(sys.exc_info()), '  ***\n')
 		return True	# set return flag on error.
-	# end of accessing record file.
-#_ end of _read_TimestampJSONRecords ______________________________________________
+	# end of opening record file.
+	repo.ui.debug(
+		'______\n', 
+		'Retrieving timestamps from JSON record file:\n', 
+		'------\n'
+		)
+	# Read in file content into local string.
+	s_Content = myTimeStampJSONFile.read()
+	myTimeStampJSONFile.close()
+	# Attempt to load JSON data with correct encoding.
+	openedEncoding = None
+	encodingList = list(('utf_8', sys.getfilesystemencoding(), 'ascii'))
+	for testEncoding in encodingList:
+		repo.ui.debug('testEncoding = ', testEncoding, '\n')
+		try:
+			myData = json.loads(unicode(s_Content, testEncoding))
+		except:
+			repo.ui.debug( \
+				'*** ', testEncoding, ' Exception: \n', \
+				str(sys.exc_info()), '\n***\n')
+			#move on to check next encoding.
+			continue
+		else:
+			openedEncoding = testEncoding
+			#valid encoding found, no need to try others.
+			break
+		# end of load attempt.
+	# end of loop through encoding list.
+	if not openedEncoding: 
+		# No encoding could be determined - Treat as failure.
+		# Allow error checking to try opening as CSV file.
+		repo.ui.debug('Failed to open as JSON file with available Encoding.\n')
+		# Try opening as a pre-v0.2.0 CSV file insted:
+		repo.ui.warn(
+			'Attempting to open ', 
+				IN_TimestampFileName, 
+				' as CSV file\n'
+				)
+		return _read_TimestampRecords(
+			repo, 
+			IN_TimestampFileName, 
+			INOUT_TimeStamp_dict
+			)
+	# Check for version and object data:
+	if ('FileData' in myData):
+		if (LastPlaceholder in myData['FileData']):
+			#Don't import placeholder into local dictionary.
+			del myData['FileData'][LastPlaceholder]
+		myWarnCount = 0 #initialize counter.
+		for s_fileName, obj_fileData in myData['FileData'].items():
+			# Convert s_fileName encode (unicode) 
+			# to sys.getfilesystemencoding()
+			s_fileName = s_fileName.encode(sys.getfilesystemencoding())
+			#Only import data for entries already in local dictionary.
+			if s_fileName in INOUT_TimeStamp_dict:
+				myWarn = False #initialize warning flag for each item.
+				#Make sure incoming data is properly formatted.
+				if isinstance(obj_fileData, float):
+					# Keep this section for compatibility 
+					# with v0.2.1 timestamp file.
+					f_fileModTime = float(obj_fileData)
+					#myErr = False 	# no return flag as successful.
+				elif isinstance(obj_fileData, dict):
+					# As of v0.2.2, file data is stored within
+					# a dict object for future extensibility.
+					if ('timestamp' in obj_fileData):
+						f_fileModTime = float(obj_fileData['timestamp'])
+						#myErr = False 	# no return flag as successful.
+					else: # Error - missing timestamp in dictionary.
+						# use explicitly invalid value if none found.
+						f_fileModTime = -1 
+						myWarn = True
+						repo.ui.warn(
+							'WARNING: ', 
+							'Missing timestamp definition for ', 
+							str(s_fileName), ': ', 
+							str(obj_fileData), '\n'
+							)
+				else: # Error - not a recognized data type.
+					# use explicitly invalid value if none found.
+					f_fileModTime = -1 
+					myWarn = True
+					repo.ui.warn(
+						'WARNING: Undefined data for ', 
+						str(s_fileName), ': ', 
+						str(type(obj_fileData)), 
+						' = [', str(obj_fileData), ']\n'
+						)
+				# end of check for data type
+				if not myWarn:
+					INOUT_TimeStamp_dict[str(s_fileName)] = \
+						f_fileModTime
+					repo.ui.debug(
+						'UTC: ', str(f_fileModTime), 
+						'\t: ', str(s_fileName), '\n'
+						)
+				else:
+					myWarnCount += 1 # increment count of problem reads.
+				# end of check for per-item warning.
+			# end of check file exists in dictionary.
+		# end of loop through items.
+		if (len(myData['FileData']) <= 0):
+			# This is not an error condition.
+			# Likely just an empty working directory.
+			repo.ui.debug(
+				IN_TimestampFileName, 
+				' contains no file records', 
+				' - Working Directory is empty?\n'
+				)
+		elif (myWarnCount >= len(myData['FileData'])):
+			repo.ui.debug(
+				'ERROR: Could not read file data from ', 
+				IN_TimestampFileName, '\n'
+				)
+			myErr = True	# Error - could not find JSON data
+		# end of check warning count.
+	else: # JSON file data is not present
+		repo.ui.debug(
+			IN_TimestampFileName, 
+			' does not have JSON file data.\n'
+			)
+		myErr = True	# Error - could not find JSON FileData records
+	# end of check for file data.
+	if myErr: #error return detected
+		repo.ui.warn('Failed to read JSON file.\n')
+	# end of final error check
+	return myErr
+#_ end of _read_TimestampJSONRecords _________________________________________
 
 
-#==============================================================================
+#=============================================================================
 # _save_TimestampsJSON Function Definition
-#------------------------------------------------------------------------------
-# Summary: Save File Modified Timestamp data for files in the global dictionary
-#	collection to a JSON-formatted record file in the repository root directory.  
-#	New values for timestamps will be retrieved for files that have changed or 
-#	are missing timestamp records in the first place.
+#-----------------------------------------------------------------------------
+# Summary: Save File Modified Timestamps for files in the global dictionary
+#	object to a JSON-formatted record file in the repository root directory. 
+#	New values for timestamps will be retrieved for files that have changed 
+#	or are missing timestamp records in the first place.
 # NOTES:
-# * Many thanks to BitBucket user lboehler (https://bitbucket.org/lboehler) for
-#	suggesting using the SORTED list to build the timestamp file.  This really 
-#	should have been obvious, but I completely overlooked it!  
+# * Many thanks to BitBucket user lboehler (https://bitbucket.org/lboehler)
+#	for suggesting using the SORTED list to build the timestamp file.  This 
+#	really should have been obvious, but I completely overlooked it!  
 # * The JSON file will be built manually instead of using the built-in JSON 
 #	methods.  This is because the dict object in Python can no be sorted well
 #	enough to generate a repeatable JSON file with the data in the same order
 #	all the time.  Maybe when Mercurial starts using Python 2.7+, the newer 
 #	OrderedDict object type may be able to be used here.
-#==============================================================================
-def _save_TimestampsJSON(repo, IN_TimestampFileName, IN_ChangedList, IN_DroppedList, INOUT_TimeStamp_dict):
+#=============================================================================
+def _save_TimestampsJSON(
+		repo, 
+		IN_TimestampFileName, 
+		IN_MatchList, 
+		IN_ChangedList, 
+		IN_DroppedList, 
+		INOUT_TimeStamp_dict
+		):
 	'''Save File Modification Timestamps to JSON record file.'''
-	repo.ui.note('______\nSaving timestamps to JSON file...\n------\n')
+	repo.ui.note(
+		'______\n', 
+		'Saving timestamps to JSON file...\n', 
+		'------\n'
+		)
 	# Remove the record file from the list.
 	#	It causes confusion and difficulty during merge.
 	if IN_TimestampFileName in INOUT_TimeStamp_dict:
 	# end of check for record file.
 	myTimeStampJSONFile = open(repo.wjoin(IN_TimestampFileName), 'w')
 	# Record version data for the file.
-	myTimeStampJSONFile.write('{\n"Version": "' + File_Version + '",\n"FileData":{\n')
+	myTimeStampJSONFile.write(
+		'{\n"Version": "' +
+		File_Version +
+		'",\n"FileData":{\n'
+		)
 	# Make sure to use a sorted dictionary for the file data:
 	for s_fileName in sorted(INOUT_TimeStamp_dict.keys(), key=str.lower):
 		f_fileModTime = INOUT_TimeStamp_dict[s_fileName]
 		if (s_fileName in IN_ChangedList) or (f_fileModTime<=0):
-			f_fileModTime = INOUT_TimeStamp_dict[s_fileName] = _get_fileModTime(repo, s_fileName)
+			# Make sure to only save new file timestamps if they have  
+			# been included in the commit (will be in the match list).
+			if (f_fileModTime>0) and \
+					(len(IN_MatchList)>0) and \
+					(s_fileName not in IN_MatchList):
+				# Do not save new timestamp if file is not in match list.
+				pass
+			else: 
+				#File is in match list, 
+				# or match list is empty (save all timestamps)
+				f_fileModTime = \
+					INOUT_TimeStamp_dict[s_fileName] = \
+					_get_fileModTime(repo, s_fileName)
+			# end of check for file in match list
 		# end of update timestamps for changed items or missing timestamps.
 		if (s_fileName in IN_DroppedList) or (f_fileModTime<=0):
-			repo.ui.debug('...removing record of dropped file, or file with missing timestamp (', s_fileName, ')\n')
+			repo.ui.debug(
+				'...removing record of dropped file, ', 
+				'or file with missing timestamp ', 
+				'(', s_fileName, ')\n'
+				)
 			del INOUT_TimeStamp_dict[s_fileName]
 		else:	#timestamp is valid
-			myTimeStampJSONFile.write('"%s": {"timestamp": %s},\n' % (s_fileName, f_fileModTime))
+			myTimeStampJSONFile.write(
+				'"%s": {"timestamp": %s},\n' 
+				% (s_fileName, f_fileModTime)
+				)
 		# end of check for non-existing files or timestamps.
 	# end of loop through dictionary items.
 	# Add one last record to wrap up the JSON formatting.
-	myTimeStampJSONFile.write('"' + LastPlaceholder + '": {"timestamp": 0}\n}\n}')
+	myTimeStampJSONFile.write(
+		'"' + LastPlaceholder +
+		'": {"timestamp": 0}' +
+		'\n}\n}'
+		)
 	# Make sure to close the file!
 	myTimeStampJSONFile.close()
-#_ end of _save_TimestampsJSON ____________________________________________________
+#_ end of _save_TimestampsJSON _______________________________________________
 
 
-#==============================================================================
+#=============================================================================
 # _restore_Timestamps Function Definition
-#------------------------------------------------------------------------------
+#-----------------------------------------------------------------------------
 # Summary: Restore the File Modification Timestamp property for files in the
 #	global dictionary collection.  
-# NOTE: This presumes that the dictionary has been initialized and the original
+# NOTE: This presumes that the dictionary has been initialized and original
 #	timestamp data has already been read into the dictionary.
-#==============================================================================
+#=============================================================================
 def _restore_Timestamps(repo, IN_TimeStamp_dict):
 	'''Restore File Modification Timestamps from record file.'''
 	repo.ui.note('______\nRestoring timestamps...\n------\n')
 			repo.ui.debug(s_fileName, ' - skipped - no timestamp recorded\n')
 		# end of check for valid timestamp.
 	# end of loop through dictionary items.
-#_ end of _restore_Timestamps _________________________________________________
+#_ end of _restore_Timestamps ________________________________________________
 
 
-
-#==============================================================================
+#=============================================================================
 # _display_Timestamps Function Definition
-#------------------------------------------------------------------------------
-# Summary: Default action.  Display the File Modification Timestamp property for
+#-----------------------------------------------------------------------------
+# Summary: Default action. Display File Modification Timestamp property for
 #	files in the global dictionary collection.  
-# NOTE: This presumes that the dictionary has been initialized and the original
+# NOTE: This presumes that the dictionary has been initialized and original
 #	timestamp data has already been read into the dictionary.
-#==============================================================================
+#=============================================================================
 def _display_Timestamps(repo, myTimeStamp_dict):
 	'''Display File Timestamps currently recorded.'''
 	repo.ui.note('______\nDisplaying timestamps...\n------\n')
 		if (f_fileModTime>0):
 			# Valid timestamp detected!
 			# Display timestamp using local time adjustment.
-			repo.ui.note(time.strftime("%Y.%m.%d %H:%M:%S", time.localtime(f_fileModTime)), " \t", s_fileName, "\n")
+			repo.ui.note(
+				time.strftime('%Y.%m.%d %H:%M:%S', 
+					time.localtime(f_fileModTime)
+					), 
+				' \t', s_fileName, '\n'
+				)
 		else:
 			# No valid timestamp recorded, skip this file.
-			repo.ui.debug(s_fileName, ' - skipped - no timestamp recorded\n')
+			repo.ui.debug(
+				s_fileName, 
+				' - skipped - no timestamp recorded\n'
+				)
 		# end of check for valid timestamp.
 	# end of loop through dictionary items.
-#_ end of _display_Timestamps _________________________________________________
+#_ end of _display_Timestamps ________________________________________________
 
 
-#==============================================================================
+#=============================================================================
 # _check_Merge_unresolved Function Definition
-#------------------------------------------------------------------------------
-# Summary: Check the repository's MergeState to see if there are any unresolved
-# files and return True if any unresolved files are found (False otherwise).
-#==============================================================================
+#-----------------------------------------------------------------------------
+# Summary: Check the repository's MergeState for any unresolved files
+# and return True if any unresolved files are found (False otherwise).
+#=============================================================================
 def _check_Merge_unresolved(repo):
 	'''Determine if there are unresolved files after a merge.'''
 	repo.ui.debug('...checking for unresolved files...\n')
 			return True
 	#end of loop through mergestate files
 	return False #will get to here if no unresolved files.
-#_ end of _check_Merge_unresolved _____________________________________________
+#_ end of _check_Merge_unresolved ____________________________________________