Mercurial and Git clients can push and pull from this alias URL to interact with this repository. You can change to which repository an alias points by going to the Aliases link on the project page.
# Creates a task-bar icon. Run from Python.exe to see the# messages printed. Takes an optional logfile as first command# line parameterimportsysifhasattr(sys,"frozen"):classBlackHole(object):closed=Truesoftspace=0defwrite(self,data):passdefclose(self):passdefflush(self):passsys.stdout=BlackHole()sys.stderr=BlackHole()importosimporterrnoimporttimeimportthreadingimportcStringIOimportQueueimporttracebackimportgctry:fromwin32apiimport*fromwin32guiimport*importwin32pipeimportwin32conimportwin32eventimportwin32fileimportwinerrorimportpywintypesimportwin32securityexceptImportError,e:print'Fatal error at startup',esys.exit(1)frommercurialimportdemandimportdemandimport.ignore.append('win32com.shell')demandimport.enable()frommercurialimportui,errorfrommercurial.windowsimportposixfile,unlink,renamefromtortoisehg.util.i18nimportagettextas_fromtortoisehg.utilimportthread2,paths,shlib,versionAPP_TITLE=_('TortoiseHg Overlay Icon Server')EXIT_CMD=1025classLogger():def__init__(self):self.file=Nonedefsetfile(self,name):oname=name+'.old'try:rename(name,oname)except:passself.file=posixfile(name,'wb')self.msg('%s, Version %s'%(APP_TITLE,version.version()))self.msg('Logging to file started')defmsg(self,msg):ts='[%s] '%time.strftime('%c')f=self.fileiff:f.write(ts+msg+'\n')f.flush()os.fsync(f.fileno())print'L'+ts+msgelse:printts+msglogger=Logger()defSetIcon(hwnd,name,add=False):# Try and find a custom iconif'--noicon'insys.argv:returnprint"SetIcon(%s)"%namehinst=GetModuleHandle(None)fromtortoisehg.util.pathsimportget_tortoise_iconiconPathName=get_tortoise_icon(name)ificonPathNameandos.path.isfile(iconPathName):icon_flags=win32con.LR_LOADFROMFILE|win32con.LR_DEFAULTSIZEhicon=LoadImage(hinst,iconPathName,win32con.IMAGE_ICON,0,0,icon_flags)else:print"Can't find a Python icon file - using default"hicon=LoadIcon(0,win32con.IDI_APPLICATION)flags=NIF_ICON|NIF_MESSAGE|NIF_TIPnid=(hwnd,0,flags,win32con.WM_USER+20,hicon,APP_TITLE)action=NIM_MODIFYifadd:action=NIM_ADDtry:Shell_NotifyIcon(action,nid)exceptpywintypes.error:# This is common when windows is starting, and this code is hit# before the taskbar has been created.print"Failed to add the taskbar icon - is explorer running?"# but keep running anyway - when explorer starts, we get the# TaskbarCreated message.classMainWindow:def__init__(self):self.pipethread=Nonemsg_TaskbarRestart=RegisterWindowMessage("TaskbarCreated");message_map={msg_TaskbarRestart:self.OnRestart,win32con.WM_DESTROY:self.OnDestroy,win32con.WM_COMMAND:self.OnCommand,win32con.WM_USER+20:self.OnTaskbarNotify,}# Register the Window class.wc=WNDCLASS()hinst=wc.hInstance=GetModuleHandle(None)wc.lpszClassName="THgRpcServer"wc.style=win32con.CS_VREDRAW|win32con.CS_HREDRAW;wc.hCursor=LoadCursor(0,win32con.IDC_ARROW)wc.hbrBackground=win32con.COLOR_WINDOWwc.lpfnWndProc=message_map# could also specify a wndproc.classAtom=RegisterClass(wc)# Create the Window.style=win32con.WS_OVERLAPPED|win32con.WS_SYSMENUself.hwnd=CreateWindow(classAtom,APP_TITLE,style, \
0,0,win32con.CW_USEDEFAULT,win32con.CW_USEDEFAULT, \
0,0,hinst,None)UpdateWindow(self.hwnd)self._DoCreateIcons()def_DoCreateIcons(self):show,highlight=get_config()ifshow:SetIcon(self.hwnd,"hg.ico",add=True)# start namepipe server for hg statusself.start_pipe_server()defOnRestart(self,hwnd,msg,wparam,lparam):logger.msg("MainWindow.OnRestart")self._DoCreateIcons()defOnDestroy(self,hwnd,msg,wparam,lparam):logger.msg("MainWindow.OnDestroy")nid=(self.hwnd,0)try:Shell_NotifyIcon(NIM_DELETE,nid)exceptpywintypes.error:pass# happens when we run without iconPostQuitMessage(0)# Terminate the app.defOnTaskbarNotify(self,hwnd,msg,wparam,lparam):iflparam==win32con.WM_RBUTTONUPorlparam==win32con.WM_LBUTTONUP:menu=CreatePopupMenu()# AppendMenu(menu, win32con.MF_SEPARATOR, 0, '')AppendMenu(menu,win32con.MF_STRING,EXIT_CMD,_('Exit'))pos=GetCursorPos()# See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/menus_0hdi.asptry:SetForegroundWindow(self.hwnd)TrackPopupMenu(menu,win32con.TPM_LEFTALIGN,pos[0],pos[1],0,self.hwnd,None)PostMessage(self.hwnd,win32con.WM_NULL,0,0)exceptpywintypes.error:passreturn1defOnCommand(self,hwnd,msg,wparam,lparam):id=LOWORD(wparam)ifid==EXIT_CMD:self.exit_application()else:print"Unknown command -",iddefexit_application(self):logger.msg("MainWindow.exit_application")ifself.stop_pipe_server():DestroyWindow(self.hwnd)logger.msg("Goodbye")defstop_pipe_server(self):logger.msg("MainWindow.stop_pipe_server")ifnotself.pipethread.isAlive():logger.msg("pipethread is not alive")returnTrue# Try the nice way firstself.svc.SvcStop()max_try=10cnt=1whilecnt<=max_tryandself.pipethread.isAlive():print"testing pipe [try %d] ..."%cnttry:try:self.pipethread.terminate()exceptValueError:passwin32pipe.CallNamedPipe(PIPENAME,'',PIPEBUFSIZE,0)except:logger.msg(traceback.format_exc())passcnt+=1ifself.pipethread.isAlive():msg="WARNING: unable to stop server after %d trys."%max_trylogger.msg(msg)returnFalseelse:returnTruedefstart_pipe_server(self):ifself.pipethreadisnotNone:returndefservepipe():self.svc=PipeServer(self.hwnd)self.svc.SvcDoRun()self.pipethread=thread2.Thread(target=servepipe)self.pipethread.start()PIPENAME=r"\\.\pipe\TortoiseHgRpcServer-bc0c27107423-"PIPENAME+=GetUserName()PIPEBUFSIZE=4096defgetrepos(batch):roots=set()notifypaths=set()forpathinbatch:r=paths.find_root(path)ifrisNone:try:forninos.listdir(path):r=paths.find_root(os.path.join(path,n))if(risnotNone):roots.add(r)notifypaths.add(r)exceptException,e:# This exception raises in case of fixutf8 extension enabled# and folder name contains '0x5c'(backslash).logger.msg('Failed listdir %s (%s)'%(path,str(e)))else:roots.add(r);notifypaths.add(path)returnroots,notifypathsdefupdate_batch(batch):'''updates thgstatus for all paths in batch'''roots,notifypaths=getrepos(batch)ifroots:_ui=ui.ui();failedroots=set()errorstream=cStringIO.StringIO() _stderr = sys.stderr
sys.stderr = errorstream
try:
+ # Ensure that all unset dirstate entries can be updated.+ time.sleep(2) updated_any = False
for r in sorted(roots):
try:
ifshlib.update_thgstatus(_ui,r,wait=False):updated_any=Trueshlib.shell_notify([r],noassoc=True)logger.msg('Updated '+r)except(IOError,OSError):print"IOError or OSError on updating %s (check permissions)"%rlogger.msg('Failed updating %s (check permissions)'%r)failedroots.add(r)except(error.Abort,error.ConfigError,error.RepoError,error.RevlogError,ImportError),e:logger.msg('Failed updating %s (%s)'%(r,str(e))) failedroots.add(r)
notifypaths -= failedroots
if notifypaths:
- time.sleep(2) shlib.shell_notify(list(notifypaths), noassoc=not updated_any)
logger.msg('Shell notified')
errmsg = errorstream.getvalue()
iferrmsg:logger.msg('stderr: %s'%errmsg)finally:sys.stderr=_stderrrequests=Queue.Queue(0)defget_config():show_taskbaricon=Truehgighlight_taskbaricon=Trueversion2cmenu=Falsetry:from_winregimportHKEY_CURRENT_USER,OpenKey,QueryValueExhkey=OpenKey(HKEY_CURRENT_USER,r'Software\TortoiseHg')t=('1','True')try:show_taskbaricon=QueryValueEx(hkey,'ShowTaskbarIcon')[0]intexceptEnvironmentError:passtry:hgighlight_taskbaricon=QueryValueEx(hkey,'HighlightTaskbarIcon')[0]intexceptEnvironmentError:pass# Upgrade user's context menu, once per major releasetry:version2cmenu=QueryValueEx(hkey,'ContextMenuVersion')[0]=='2'exceptEnvironmentError:passtry:ifnotversion2cmenu:from_winregimportCreateKey,SetValueEx,REG_SZtry:promoted=QueryValueEx(hkey,'PromotedItems')[0]exceptEnvironmentError:promoted=''plist=[i.strip()foriinpromoted.split(',')]hkey=CreateKey(HKEY_CURRENT_USER,r'Software\TortoiseHg')ifu'log'inplist:idx=plist.index(u'log')plist[idx]=u'workbench'SetValueEx(hkey,'PromotedItems',0,REG_SZ,','.join(plist))SetValueEx(hkey,'ContextMenuVersion',0,REG_SZ,'2')exceptEnvironmentError:passexcept(ImportError,WindowsError):passreturn(show_taskbaricon,hgighlight_taskbaricon)defupdate(args,hwnd):batch=[]r=args[0]print"got update request %s (first in batch)"%rbatch.append(r)print"wait a bit for additional requests..."show,highlight=get_config()ifshowandhighlight:SetIcon(hwnd,"hgB.ico")time.sleep(0.2)deferred_requests=[]try:whileTrue:req=requests.get_nowait()s=req.split('|')cmd,args=s[0],s[1:]ifcmd=='update':print"got update request %s"%reqbatch.append(args[0])else:deferred_requests.append(req)exceptQueue.Empty:passforreqindeferred_requests:requests.put(req)msg="processing batch with %i update requests"printmsg%len(batch)update_batch(batch)ifshowandhighlight:SetIcon(hwnd,"hg.ico")defremove(args):path=args[0]logger.msg('Removing '+path)roots,notifypaths=getrepos([path])ifroots:forrinsorted(roots):tfn=os.path.join(r,'.hg','thgstatus')try:f=posixfile(tfn,'rb')e=f.readline()f.close()ifnote.startswith('@@noicons'):unlink(tfn)except(IOError,OSError),e:ife.errno!=errno.ENOENT:logger.msg("Error while trying to remove %s (%s)"%(tfn,e))ifnotifypaths:shlib.shell_notify(list(notifypaths))defdispatch(req,cmd,args,hwnd):print"dispatch(%s)"%reqifcmd=='update':update(args,hwnd)elifcmd=='remove':remove(args)elifcmd=='error':logger.msg("**** Error: %s"%args[0])else:logger.msg("**** Error: unknown request '%s'"%req)classUpdater(threading.Thread):def__init__(self,hwnd):threading.Thread.__init__(self)self.hwnd=hwnddefrun(self):whileTrue:req=requests.get()s=req.split('|')cmd,args=s[0],s[1:]ifcmd=='terminate':logger.msg('Updater thread terminating')returndispatch(req,cmd,args,self.hwnd)gc.collect()classPipeServer:def__init__(self,hwnd):self.hwnd=hwndself.updater=Updater(hwnd)self.updater.start()# Create an event which we will use to wait on.# The "service stop" request will set this event.self.hWaitStop=win32event.CreateEvent(None,0,0,None)# We need to use overlapped IO for this, so we dont block when# waiting for a client to connect. This is the only effective way# to handle either a client connection, or a service stop request.self.overlapped=pywintypes.OVERLAPPED()# And create an event to be used in the OVERLAPPED object.self.overlapped.hEvent=win32event.CreateEvent(None,0,0,None)defSvcStop(self):logger.msg("PipeServer.SvcStop")win32event.SetEvent(self.hWaitStop)requests.put('terminate|')defSvcDoRun(self):logger.msg("PipeServer.SvcDoRun")# We create our named pipe.pipeName=PIPENAMEopenMode=win32pipe.PIPE_ACCESS_DUPLEX|win32file.FILE_FLAG_OVERLAPPEDpipeMode=win32pipe.PIPE_TYPE_MESSAGE# When running as a service, we must use special security for the pipesa=pywintypes.SECURITY_ATTRIBUTES()# Say we do have a DACL, and it is empty# (ie, allow full access!)sa.SetSecurityDescriptorDacl(1,None,0)pipeHandle=win32pipe.CreateNamedPipe(pipeName,openMode,pipeMode,win32pipe.PIPE_UNLIMITED_INSTANCES,0,0,6000,# default buffers, and 6 second timeout.sa)# Loop accepting and processing connectionswhileTrue:try:hr=win32pipe.ConnectNamedPipe(pipeHandle,self.overlapped)exceptpywintypes.error,inst:logger.msg("Error connecting pipe: %s"%inst)pipeHandle.Close()breakifhr==winerror.ERROR_PIPE_CONNECTED:# Client is fast, and already connected - signal eventwin32event.SetEvent(self.overlapped.hEvent)# Wait for either a connection, or a service stop request.timeout=win32event.INFINITEwaitHandles=self.hWaitStop,self.overlapped.hEventrc=win32event.WaitForMultipleObjects(waitHandles,0,timeout)ifrc==win32event.WAIT_OBJECT_0:# Stop eventreturnelse:# read pipe and process requesttry:hr,data=win32file.ReadFile(pipeHandle,PIPEBUFSIZE)ifnotdata:raiseSystemExit# signal by dispatch terminatewin32pipe.DisconnectNamedPipe(pipeHandle)exceptwin32file.error:# Client disconnected without sending data# or before reading the response.# Thats OK - just get the next connectioncontinuetry:requests.put(data)ifdata=='terminate|':logger.msg('PipeServer received terminate from pipe')PostMessage(self.hwnd,win32con.WM_COMMAND,EXIT_CMD,0)breakexceptSystemExit:raiseSystemExit# interrupted by thread2.terminate()except:logger.msg("WARNING: something went wrong in requests.put")logger.msg(traceback.format_exc())status="ERROR"# Clean up when we exitself.SvcStop()RUNMUTEXNAME='thgtaskbar-'+GetUserName()defehook(etype,values,tracebackobj):elist=traceback.format_exception(etype,values,tracebackobj)logger.msg(''.join(elist))defmain():args=sys.argv[1:]sa=win32security.SECURITY_ATTRIBUTES()sa.SetSecurityDescriptorDacl(1,None,0)# allow full accessrunmutex=win32event.CreateMutex(sa,1,RUNMUTEXNAME)ifGetLastError()==winerror.ERROR_ALREADY_EXISTS:print"another instance is already running"returnlogfilename=Noneforarginargs:ifarg[0]=='-':passelse:logfilename=argiflogfilename:logger.setfile(logfilename)else:try:fromwin32com.shellimportshell,shellconappdir=shell.SHGetSpecialFolderPath(0,shellcon.CSIDL_APPDATA)exceptpywintypes.com_error:appdir=os.environ['APPDATA']logfilename=os.path.join(appdir,'TortoiseHg','OverlayServerLog.txt')try:os.makedirs(os.path.dirname(logfilename))exceptEnvironmentError:passlogger.setfile(logfilename)sys.excepthook=ehookw=MainWindow()PumpMessages()if__name__=='__main__':main()
Attach a Trello Card
Add a tag
Your session has expired
You are no longer logged in. Please log in and try your request again.
Filter RSS Feed
This RSS feed URL allows you to see the contents of your current filter using any feed reader.
This link includes a special authentication token. If you share the URL with anyone else, they can see this RSS feed's activity. You can disable these tokens when needed.
Your current filter is unsaved; changing it won't affect this RSS feed.