Nathan Durnan committed 7702c14 Merge

Merge with Release 0.1.5

Comments (0)

Files changed (3)

+About (version 0.1.5 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-
     post-merge.TimestampMod = python:/path/to/
     post-resolve.TimestampMod = python:/path/to/
+    post-revert.TimestampMod = python:/path/to/
 Nothing further is required to make the extension work.  It will set up it's 
 own hooks that will trigger during committing and updating actions automatically.
 file for TortoiseHg.  
-Optional Behavior
-(under construction...)
+!!! Known Issues !!!
+Every attempt is made to keep this extension up-to-date and in working order,
+but there are occasional problems that arise in the development process.  These
+issues will be noted here, and possible work-around recommendations provided if
+at all possible.
+* Support has been added for restoring timestamps of individual files or groups 
+  of files when the "Revert" command is used.  This features works well using
+  Mercurial directly (command-line), but does not work at all for most TortoiseHg
+  menu command and dialogs.  As of TortoiseHg 2.2.2, there is an `outstanding issue 
+  <>`_ 
+  with how the "Revert" command has been implemented within TortiseHg that does not 
+  allow it to take advantage of the hooks from extensions like this one.  
+  Currently (TortoiseHg 2.2.2), the only command that seems to work from TortoiseHg 
+  is the Windows Explorer context menu "TortiseHg > Revert Files..." item.
+* Because the timestamp record file is modified on *every* commit, there are
+  nearly always merge conflicts with the timestamp file.  Most of the time, these
+  are trivial and can be resolved with a simple "Tool Resolve" option.  Manually 
+  resolving the differences is not too difficult either.  Just keep in mind that 
+  a larger timestamp number means a newer timestamp.  This issue can affect any 
+  commands that involve merging such as graft or import (when dealing with patches).
+  No further work will be done on this issue.  After spending much time imagining 
+  how this could be automated, it was decided that it is best left to the user to 
+  determine the most appropriate timestamps to keep when merging the timestamp file.
 Further Reading
 # - Automatically save and restore the modification times of files
-# Version 0.1.4  --> !!BETA RELEASE!!!
+# Version 0.1.5  --> !!BETA RELEASE!!!
 # Copyright 2011-2012 Nathan Durnan <>
 # Based on timestamp extension by Friedrich Kastner-Masilko <>
 import os	#required for filesystem access methods.
 import time	#required for time functions.
 from mercurial import localrepo	#required for creating a pseudo-pre-commit hook.
-from mercurial import scmutil	#required for "match" object in commit wrapper.
+from mercurial import match as matchmod	#required for "match" object in commit wrapper.
+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_____________________________________________________
 	# Hook_Pre_Commit is depreciated in favor of Wrap_Commit method
 	#	(Wrap_Commit works with both native Mercurial and TortoiseHg.)
 	'''ui.setconfig("hooks", "pre-commit.TimestampMod", Hook_Pre_Commit)'''
-	#NOTE: the post-merge and post-resolve hooks are not picked up by TortoiseHg.
-	#  When using this extension with TortoiseHg, these hooks must be manually
-	#  added to the "mercurial.ini" configuration file.  
+	#NOTE: the post-merge, post-resolve, and post-revert hooks are not picked up 
+	#  by TortoiseHg.  When using this extension with TortoiseHg, these hooks 
+	#  must be manually added to the "mercurial.ini" configuration file.  
 	#  Use the following format:
 	#    [hooks]
 	#    post-merge.TimestampMod = python:{}:Hook_Post_Merge
 	#    post-resolve.TimestampMod = python:{}:Hook_Post_Resolve
+	#    post-revert.TimestampMod = python:{}:Hook_Post_Revert
 	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 _____________________________________________________________
 		# Make sure the match object is created.
 		if not match:
 			repo.ui.debug('Empty match: Must create!\n')
-			match = scmutil.matchfiles(repo, "")  #create an empty match object
+			match = matchmod.always(repo.root, '') #create an empty match object
 		# End of check for non-existent match object.
 		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):
+	'''NOTE: TortoiseHg Incompatibility Issue!
+	The Post-Revert hook does not work correctly for most of the Revert 
+	commands from TortoiseHg (version 2.2.2 at the time of implementaion).
+	The hook simply does not fire from the methods used within TortoiseHg.
+	This issue has been brought to the attention of the TortoiseHg team and
+	is on their list of items that need fixed:
+	'''
+	repo.ui.note("TimestampMod|Post-Revert Hook accessed!\n")
+	repo.ui.debug("-----\nPost-Revert:kwargs = \n", str(kwargs), "\n-----\n")
+	bDryRun = False #starting value
+	bAll = False #starting value
+	listExclude = list()
+	if ('opts' in kwargs):
+		bDryRun = kwargs['opts'].get('dry_run', False)
+		bAll = kwargs['opts'].get('all', False)
+		listExclude = kwargs['opts'].get('exclude', list())
+		if kwargs['opts'].get('date'):
+			#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'])
+		#end of check for date specified.
+	#end of check for 'opts' keyword.
+	#Create a temporary copy of the timestamp file from the source revision.
+, 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)
+		for myFile in listExclude:
+			if myFile in TimeStamp_dict:
+				del TimeStamp_dict[myFile]
+			#end of check for file in dictionary.
+		#loop through exclude filter
+	else: #only specific files have been reverted.
+		TimeStamp_dict.clear()
+		for myFile in kwargs['pats']:
+			myFileName = str(myFile).strip()
+			TimeStamp_dict[myFileName] = -1
+		#end of loop through pattern list
+	#end of check for 'all' flag
+	# Retrieve existing timestamps from the record file.
+	myErr = _read_TimestampRecords(repo, (File_TimestampRecords + '.revert'), TimeStamp_dict)
+	if (not bDryRun):
+		if not myErr:
+			_restore_Timestamps(repo, TimeStamp_dict)
+		#end of check for file-read error.
+	#end of check for dry-run operation.
+	#Delete temporary timestamp file
+	try:
+		os.unlink(repo.wjoin(File_TimestampRecords + '.revert'))
+	except:
+		repo.ui.status("Post-Revert: error deleting timestamp file!\n")
+	#end of deleting temporary timestamp file.
 #_ end of Hook Functions ______________________________________________________
 	# end of check for match argument'''
 	myChangedList, myDroppedList = _get_RepoFileList(repo, myMatchList, TimeStamp_dict)
 	# Retrieve existing timestamps from the record file.
-	myRet = _read_TimestampRecords(repo, File_TimestampRecords, TimeStamp_dict)
+	myErr = _read_TimestampRecords(repo, File_TimestampRecords, TimeStamp_dict)
 	# Check for command optional argument
 	if kwargs['save']:
 		_save_Timestamps(repo, File_TimestampRecords, myChangedList, TimeStamp_dict)
-	elif myRet:	# Only evaluate Restore or Display if file was read.
+	elif not myErr:	# Only evaluate Restore or Display if file was read.
 		if kwargs['restore']:
 			_restore_Timestamps(repo, TimeStamp_dict)
 	myTimeStampRecordsFile = ''
 		myTimeStampRecordsFile = open(repo.wjoin(IN_TimestampFileName), 'r')
-		repo.ui.debug('______\nRetrieveing timestamps from record file:\n------\n')
+		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])
 			# end of read data from line.
 		# end of readlines from record file.
-		return True 	# Set return flag as successful.
+		return False 	# no return flag as successful.
 		repo.ui.debug('*** Error accessing ', IN_TimestampFileName, ' file! ***\n')
 		repo.ui.debug('*** Exception: ', str(sys.exc_info()), '  ***\n')
-		return False	# Make sure return flag is not set.
+		return False	# set return flag on error.
 	# end of accessing record file.
 #_ end of _read_TimestampRecords ______________________________________________