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.
# sync.py - TortoiseHg's sync widget## Copyright 2010 Adrian Buehlmann <adrian@cadifra.com># Copyright 2010 Steve Borho <steve@borho.org>## This software may be used and distributed according to the terms of the# GNU General Public License version 2 or any later version.importosimportreimporttempfileimporturlparsefromPyQt4.QtCoreimport*fromPyQt4.QtGuiimport*frommercurialimporthg,ui,url,util,error,demandimportfrommercurialimportmergeasmergemodfromtortoisehg.utilimporthglib,wconfig,pathsfromtortoisehg.hgqt.i18nimport_fromtortoisehg.hgqtimportqtlib,cmdui,thgrepo,rebase,resolve,hgrcutildefparseurl(path):ifpath.startswith('ssh://'):scheme='ssh'p=path[len('ssh://'):]user,passwd=None,Noneifp.find('@')!=-1:user,p=tuple(p.rsplit('@',1))ifuser.find(':')!=-1:user,passwd=tuple(user.rsplit(':',1))m=re.match(r'([^:/]+)(:(\d+))?(/(.*))?$',p)ifm:host=m.group(1) port = m.group(3)
folder = m.group(5) or '.'
else:
- qtlib.WarningMsgBox(_('Malformed ssh URL'), hglib.tounicode(path))
+ qtlib.WarningMsgBox(_('Malformed ssh URL'), hglib.tounicode(path),+ parent=self)
host, port, folder = '', '', ''
elif path.startswith(('http://', 'https://', 'svn+https://')):
snpaqf = urlparse.urlparse(path)
scheme,netloc,folder,params,query,fragment=snpaqfhost,port,user,passwd=hglib.netlocsplit(netloc)iffolder.startswith('/'):folder=folder[1:]else:user,host,port,passwd=['']*4folder=pathscheme='local'returnuser,host,port,folder,passwd,schemeclassSyncWidget(QWidget,qtlib.TaskWidget):syncStarted=pyqtSignal()# incoming/outgoing/pull/push startedoutgoingNodes=pyqtSignal(object)incomingBundle=pyqtSignal(QString)showMessage=pyqtSignal(unicode)pullCompleted=pyqtSignal()pushCompleted=pyqtSignal()output=pyqtSignal(QString,QString)progress=pyqtSignal(QString,object,QString,QString,object)makeLogVisible=pyqtSignal(bool)beginSuppressPrompt=pyqtSignal()endSuppressPrompt=pyqtSignal()showBusyIcon=pyqtSignal(QString)hideBusyIcon=pyqtSignal(QString)def__init__(self,repo,parent,addmargin=False,**opts):QWidget.__init__(self,parent)layout=QVBoxLayout()layout.setContentsMargins(0,0,0,0)layout.setSpacing(4)self.setLayout(layout)self.setAcceptDrops(True)self._schemes=['local','ssh','http','https']if'hgsubversion'inrepo.extensions():self._schemes.append('svn+https')self.repo=repoself.finishfunc=Noneself.curuser=Noneself.default_user=Noneself.lastsshuser=Noneself.curpw=Noneself.updateInProgress=Falseself.opts={}self.cmenu=Noneself.embedded=bool(parent)self.targetargs=[]self.repo.configChanged.connect(self.configChanged)ifself.embedded:layout.setContentsMargins(2,2,2,2)else:self.setWindowTitle(_('TortoiseHg Sync'))self.setWindowIcon(qtlib.geticon('thg-sync'))self.resize(850,550)tb=QToolBar(self)tb.setStyleSheet(qtlib.tbstylesheet)self.layout().addWidget(tb)self.opbuttons=[]defnewaction(tip,icon,cb):a=QAction(self)a.setToolTip(tip)a.setIcon(qtlib.geticon(icon))a.triggered.connect(cb)self.opbuttons.append(a)tb.addAction(a)returnaself.incomingAction= \
newaction(_('Preview incoming changesets from remote repository'),'hg-incoming',self.inclicked)self.pullAction= \
newaction(_('Pull incoming changesets from remote repository'),'hg-pull',self.pullclicked)self.outgoingAction= \
newaction(_('Filter outgoing changesets to remote repository'),'hg-outgoing',self.outclicked)self.pushAction= \
newaction(_('Push outgoing changesets to remote repository'),'hg-push',lambda:self.pushclicked(True))newaction(_('Email outgoing changesets for remote repository'),'mail-forward',self.emailclicked)if'perfarce'inself.repo.extensions():a=QAction(self)a.setToolTip(_('Manage pending perforce changelists'))a.setText('P4')a.triggered.connect(self.p4pending)self.opbuttons.append(a)tb.addAction(a)tb.addSeparator()newaction(_('Unbundle'),'hg-unbundle',self.unbundle)tb.addSeparator()self.stopAction=a=QAction(self)a.setToolTip(_('Stop current operation'))a.setIcon(qtlib.geticon('process-stop'))a.triggered.connect(self.stopclicked)a.setEnabled(False)tb.addAction(a)tb.addSeparator()self.optionsbutton=QPushButton(_('Options'))self.postpullbutton=QPushButton()tb.addWidget(self.postpullbutton)tb.addWidget(self.optionsbutton)self.targetcombo=QComboBox()self.targetcombo.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Fixed)self.targetcombo.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLength)self.targetcombo.setEnabled(False)self.targetcheckbox=QCheckBox(_('Target:'))self.targetcheckbox.toggled.connect(self.targetcombo.setEnabled)ifself.embedded:tb.addSeparator()tb.addWidget(self.targetcheckbox)tb.addWidget(self.targetcombo)bottomlayout=QVBoxLayout()ifaddmargin:bottomlayout.setContentsMargins(5,5,5,5)else:bottomlayout.setContentsMargins(0,0,0,0)layout.addLayout(bottomlayout)hbox=QHBoxLayout()hbox.setContentsMargins(0,0,0,0)bottomlayout.addLayout(hbox)self.optionshdrlabel=lbl=QLabel(_('<b>Selected Options:</b>'))hbox.addWidget(lbl)self.optionslabel=QLabel()self.optionslabel.setAcceptDrops(False)hbox.addWidget(self.optionslabel)hbox.addStretch()hbox=QHBoxLayout()hbox.setContentsMargins(0,0,0,0)bottomlayout.addLayout(hbox)hbox.addWidget(QLabel(_('<b>Remote Repository:</b>')))self.urllabel=QLabel()self.urllabel.setTextInteractionFlags(Qt.TextSelectableByMouse)self.urllabel.setAcceptDrops(False)hbox.addWidget(self.urllabel)hbox.addStretch()hbox=QHBoxLayout()hbox.setContentsMargins(0,0,0,0)bottomlayout.addLayout(hbox)self.pathEditToolbar=tbar=QToolBar(_('Path Edit Toolbar'))tbar.setStyleSheet(qtlib.tbstylesheet)tbar.setIconSize(QSize(16,16))hbox.addWidget(tbar)self.schemecombo=QComboBox()forsinself._schemes:self.schemecombo.addItem(s)self.schemecombo.currentIndexChanged.connect(self.schemeChange)tbar.addWidget(self.schemecombo)tbar.addWidget(qtlib.Spacer(2,2))a=tbar.addAction(qtlib.geticon('thg-password'),_('Security'))a.setToolTip(_('Manage HTTPS connection security and user authentication'))self.securebutton=atbar.addWidget(qtlib.Spacer(2,2))fontm=QFontMetrics(self.font())self.hostentry=QLineEdit()self.hostentry.setToolTip(_('Hostname'))self.hostentry.setAcceptDrops(False)self.hostentry.setFixedWidth(30*fontm.width('9'))self.hostentry.textChanged.connect(self.refreshUrl)tbar.addWidget(self.hostentry)tbar.addWidget(qtlib.Spacer(2,2))self.HostAndPortWidgets=[self.hostentry]w=QLabel(':')tbar.addWidget(w)tbar.addWidget(qtlib.Spacer(2,2))self.HostAndPortWidgets.append(w)self.portentry=QLineEdit()self.portentry.setAcceptDrops(False)self.portentry.setToolTip(_('Port'))self.portentry.setFixedWidth(8*fontm.width('9'))self.portentry.setValidator(QIntValidator(0,65536,self.portentry))self.portentry.textChanged.connect(self.refreshUrl)tbar.addWidget(self.portentry)tbar.addWidget(qtlib.Spacer(2,2))self.HostAndPortWidgets.append(self.portentry)w=QLabel('/')tbar.addWidget(w)tbar.addWidget(qtlib.Spacer(2,2))self.HostAndPortWidgets.append(w)self.pathentry=QLineEdit()self.pathentry.setAcceptDrops(False)self.pathentry.setToolTip(_('Path'))self.pathentry.textChanged.connect(self.refreshUrl)tbar.addWidget(self.pathentry)tbar.addWidget(qtlib.Spacer(2,2))style=QApplication.style()a=tbar.addAction(style.standardIcon(QStyle.SP_DialogSaveButton),_('Save'))a.setToolTip(_('Save current URL under an alias'))self.savebutton=ahbox=QHBoxLayout()hbox.setContentsMargins(0,0,0,0)self.hgrctv=PathsTree(self,True)self.hgrctv.clicked.connect(self.pathSelected)self.hgrctv.removeAlias.connect(self.removeAlias)self.hgrctv.menuRequest.connect(self.menuRequest)pathsframe=QFrame()pathsframe.setFrameStyle(QFrame.StyledPanel|QFrame.Raised)pathsbox=QVBoxLayout()pathsbox.setContentsMargins(0,0,0,0)pathsframe.setLayout(pathsbox)lbl=QLabel(_('Paths in Repository Settings:'))pathsbox.addWidget(lbl)pathsbox.addWidget(self.hgrctv)hbox.addWidget(pathsframe)self.reltv=PathsTree(self,False)self.reltv.clicked.connect(self.pathSelected)self.reltv.menuRequest.connect(self.menuRequest)self.reltv.clicked.connect(self.hgrctv.clearSelection)self.hgrctv.clicked.connect(self.reltv.clearSelection)pathsframe=QFrame()pathsframe.setFrameStyle(QFrame.StyledPanel|QFrame.Raised)pathsbox=QVBoxLayout()pathsbox.setContentsMargins(0,0,0,0)pathsframe.setLayout(pathsbox)lbl=QLabel(_('Related Paths:'))pathsbox.addWidget(lbl)pathsbox.addWidget(self.reltv)hbox.addWidget(pathsframe)bottomlayout.addLayout(hbox,1)self.savebutton.triggered.connect(self.saveclicked)self.securebutton.triggered.connect(self.secureclicked)self.postpullbutton.clicked.connect(self.postpullclicked)self.optionsbutton.pressed.connect(self.editOptions)cmd=cmdui.Widget(notself.embedded,True,self)cmd.commandStarted.connect(self.beginSuppressPrompt)cmd.commandStarted.connect(self.commandStarted)cmd.commandFinished.connect(self.endSuppressPrompt)cmd.commandFinished.connect(self.commandFinished)cmd.makeLogVisible.connect(self.makeLogVisible)cmd.output.connect(self.output)cmd.output.connect(self.outputHook)cmd.progress.connect(self.progress)ifnotself.embedded:self.showMessage.connect(cmd.stbar.showMessage)bottomlayout.addWidget(cmd)cmd.setVisible(False)self.cmd=cmdself.reload()if'default'inself.paths:self.setUrl(self.paths['default'])self.curalias='default'else:self.setUrl('')self.curalias=Noneself.default_user=self.curuserself.lastsshuser=self.curuserdefcanswitch(self):returnnotself.targetcheckbox.isChecked()defschemeChange(self):ifself.default_user:scheme=self._schemes[self.schemecombo.currentIndex()]ifscheme=='ssh':self.default_user=self.curuserself.curuser=self.lastsshuserelse:self.curuser=self.default_userself.refreshUrl()defrefreshStatusTips(self):url=self.currentUrl(True)urlu=hglib.tounicode(url)self.incomingAction.setStatusTip(_('Preview incoming changesets from %s')%urlu)self.pullAction.setStatusTip(_('Pull incoming changesets from %s')%urlu)self.outgoingAction.setStatusTip(_('Filter outgoing changesets to %s')%urlu)self.pushAction.setStatusTip(_('Push outgoing changesets to %s')%urlu)defloadTargets(self,ctx):self.targetcombo.clear()#The parallel targetargs record is the argument list to pass to hgself.targetargs=[]selIndex=0;self.targetcombo.addItem(_('rev: %d (%s)')%(ctx.rev(),str(ctx)))self.targetargs.append(['--rev',str(ctx.rev())])fornameinself.repo.namedbranches:uname=hglib.tounicode(name)self.targetcombo.addItem(_('branch: ')+uname)self.targetcombo.setItemData(self.targetcombo.count()-1,name,Qt.ToolTipRole)self.targetargs.append(['--branch',name])ifctx.thgbranchhead()andname==ctx.branch():selIndex=self.targetcombo.count()-1fornameinself.repo._bookmarks.keys():uname=hglib.tounicode(name)self.targetcombo.addItem(_('bookmark: ')+uname)self.targetcombo.setItemData(self.targetcombo.count()-1,name,Qt.ToolTipRole)self.targetargs.append(['--bookmark',name])ifnameinctx.bookmarks():selIndex=self.targetcombo.count()-1returnselIndexdefrefreshTargets(self,rev):iftype(rev)isnotint:returnifrev>=len(self.repo):returnctx=self.repo.changectx(rev)index=self.loadTargets(ctx)ifindex<0:index=0self.targetcombo.setCurrentIndex(index)defconfigChanged(self):'Repository is reporting its config files have changed'self.reload()defeditOptions(self):dlg=OptionsDialog(self.opts,self)dlg.setWindowFlags(Qt.Sheet)dlg.setWindowModality(Qt.WindowModal)ifdlg.exec_()==QDialog.Accepted:self.opts.update(dlg.outopts)self.refreshUrl()defreload(self):# Refresh configured pathsself.paths={}fn=self.repo.join('hgrc')fn,cfg=hgrcutil.loadIniFile([fn],self)if'paths'incfg:foraliasincfg['paths']:self.paths[alias]=cfg['paths'][alias]tm=PathsModel(self.paths.items(),self)self.hgrctv.setModel(tm)# Refresh post-pullself.cachedpp=self.repo.postpullname=_('Post Pull: ')+self.repo.postpull.title()self.postpullbutton.setText(name)# Refresh related pathsknown=set()known.add(os.path.abspath(self.repo.root).lower())forpathinself.paths.values():ifhg.islocal(path):known.add(os.path.abspath(hglib.localpath(path)).lower())else:known.add(path)related={}forroot,shortnameinthgrepo.relatedRepositories(self.repo[0].node()):ifroot==self.repo.root:continueabs=os.path.abspath(root).lower()ifabsnotinknown:related[root]=shortnameknown.add(abs)ifrootinthgrepo._repocache:# repositories already opened keep their ui instances in syncrepo=thgrepo._repocache[root]ui=repo.uielifpaths.is_on_fixed_drive(root):# directly read the repository's configuration filetempui=self.repo.ui.copy()tempui.readconfig(os.path.join(root,'.hg','hgrc'))ui=tempuielse:continueforalias,pathinui.configitems('paths'):ifhg.islocal(path):abs=os.path.abspath(hglib.localpath(path)).lower()else:abs=pathifabsnotinknown:related[path]=aliasknown.add(abs)pairs=[(alias,path)forpath,aliasinrelated.items()]tm=PathsModel(pairs,self)self.reltv.setModel(tm)defrefreshUrl(self):'User has changed schema/host/port/path'ifself.updateInProgress:returnself.urllabel.setText(hglib.tounicode(self.currentUrl(True)))schemeIndex=self.schemecombo.currentIndex()forwinself.HostAndPortWidgets:w.setDisabled(schemeIndex==0)self.securebutton.setVisible(schemeIndex>=3)opts=[]foropt,valueinself.opts.iteritems():ifvalueisTrue:opts.append('--'+opt)elifvalue:opts.append('--'+opt+'='+value)self.optionslabel.setText(' '.join(opts))self.optionslabel.setVisible(bool(opts))self.optionshdrlabel.setVisible(bool(opts))defcurrentUrl(self,hidepw):scheme=self._schemes[self.schemecombo.currentIndex()]ifscheme=='local':returnhglib.fromunicode(self.pathentry.text())else:path=self.pathentry.text()host=self.hostentry.text()port=self.portentry.text()parts=[scheme,'://']ifscheme=='ssh'and'@'inhost:ifhost[0]=='@':user,host='',host[1:]else:user,host=host.split('@',1)self.curuser=hglib.fromunicode(user)self.lastsshuser=self.curuserifself.curuser:parts.append(self.curuser)ifself.curpw:parts.append(':')parts.append(hidepwand'***'orself.curpw)parts.append('@')parts.append(hglib.fromunicode(host))ifport:parts.extend([':',hglib.fromunicode(port)])parts.extend(['/',hglib.fromunicode(path)])return''.join(parts)defpathSelected(self,index):path=index.model().realUrl(index)self.setUrl(path)aliasindex=index.sibling(index.row(),0)alias=aliasindex.data(Qt.DisplayRole).toString()self.curalias=hglib.fromunicode(alias)defsetUrl(self,newurl):'User has selected a new URL: newurl is expected in local encoding'try:user,host,port,folder,passwd,scheme=parseurl(newurl)exceptTypeError:returnself.updateInProgress=Truefori,valinenumerate(self._schemes):ifscheme==val:self.schemecombo.setCurrentIndex(i)breakself.hostentry.setText(hglib.tounicode(hostor''))self.portentry.setText(hglib.tounicode(portor''))self.pathentry.setText(hglib.tounicode(folderor''))self.curuser=userself.curpw=passwdself.updateInProgress=Falseself.refreshUrl()self.refreshStatusTips()defdragEnterEvent(self,event):data=event.mimeData()ifdata.hasUrls()ordata.hasText():event.setDropAction(Qt.CopyAction)event.acceptProposedAction()defdragMoveEvent(self,event):data=event.mimeData()ifdata.hasUrls()ordata.hasText():event.setDropAction(Qt.CopyAction)event.acceptProposedAction()defdropEvent(self,event):data=event.mimeData()ifdata.hasUrls():url=data.urls()[0]lurl=hglib.fromunicode(url.toString())event.setDropAction(Qt.CopyAction)event.accept()elifdata.hasText():text=data.text()lurl=hglib.fromunicode(text)event.setDropAction(Qt.CopyAction)event.accept()else:returniflurl.startswith('file:///'):lurl=lurl[8:]self.setUrl(lurl)defcanExit(self):returnnotself.cmd.core.running()@pyqtSlot(QPoint,QString,QString,bool)defmenuRequest(self,point,url,alias,editable):'menu event emitted by one of the two URL lists'ifnotself.cmenu:acts=[]menu=QMenu(self)fortext,cb,iconin((_('Explore'),self.exploreurl,'system-file-manager'),(_('Terminal'),self.terminalurl,'utilities-terminal'),(_('Remove'),self.removeurl,'menudelete')):act=QAction(text,self)act.setIcon(qtlib.getmenuicon(icon))act.triggered.connect(cb)acts.append(act)menu.addAction(act)self.cmenu=menuself.acts=actsself.menuurl=urlself.menualias=aliasself.acts[-1].setEnabled(editable)self.cmenu.exec_(point)defexploreurl(self):url=hglib.fromunicode(self.menuurl)u,h,p,folder,pw,scheme=parseurl(url)ifscheme=='local':QDesktopServices.openUrl(QUrl.fromLocalFile(folder))else:QDesktopServices.openUrl(QUrl(url))defterminalurl(self):url=hglib.fromunicode(self.menuurl)u,h,p,folder,pw,scheme=parseurl(url)ifscheme!='local':qtlib.InfoMsgBox(_('Repository not local'),_('A terminal shell cannot be opened for remote'))returnqtlib.openshell(folder,'repo '+folder)defremoveurl(self):ifqtlib.QuestionMsgBox(_('Confirm path delete'),_('Delete %s from your repo configuration file?')%self.menualias,parent=self):self.removeAlias(self.menualias)defkeyPressEvent(self,event):ifevent.matches(QKeySequence.Refresh):self.reload()elifevent.key()==Qt.Key_Escape:ifself.cmd.core.running():self.cmd.cancel()elifnotself.embedded:self.close()else:returnsuper(SyncWidget,self).keyPressEvent(event)defstopclicked(self):ifself.cmd.core.running():self.cmd.cancel()defsaveclicked(self):ifself.curalias:alias=self.curaliaselif'default'notinself.paths:alias='default'else:alias='new'url=self.currentUrl(False)safeurl=self.currentUrl(True)dlg=SaveDialog(self.repo,alias,url,safeurl,self)dlg.setWindowFlags(Qt.Sheet)dlg.setWindowModality(Qt.WindowModal)ifdlg.exec_()==QDialog.Accepted:self.curalias=hglib.fromunicode(dlg.aliasentry.text())defsecureclicked(self):dlg=SecureDialog(self.repo,self.currentUrl(False),self)dlg.setWindowFlags(Qt.Sheet)dlg.setWindowModality(Qt.WindowModal)dlg.exec_()defcommandStarted(self):forbinself.opbuttons:b.setEnabled(False)self.stopAction.setEnabled(True)ifself.embedded:self.showBusyIcon.emit('thg-sync')else:self.cmd.setShowOutput(True)self.cmd.setVisible(True)defcommandFinished(self,ret):self.hideBusyIcon.emit('thg-sync')self.repo.decrementBusyCount()forbinself.opbuttons:b.setEnabled(True)self.stopAction.setEnabled(False)ifself.finishfunc:output=self.cmd.core.rawoutput()self.finishfunc(ret,output)defrun(self,cmdline,details):ifself.cmd.core.running():returnself.lastcmdline=list(cmdline)fornameinlist(details)+['remotecmd']:val=self.opts.get(name)ifnotval:continueifisinstance(val,bool):ifval:cmdline.append('--'+name)elifval:cmdline.append('--'+name)cmdline.append(val)if'rev'indetailsand'--rev'notincmdline:ifself.embeddedandself.targetcheckbox.isChecked():idx=self.targetcombo.currentIndex()ifidx!=-1andidx<len(self.targetargs):args=self.targetargs[idx]ifargs[0][2:]notindetails:args[0]='--rev'cmdline+=argsifself.opts.get('noproxy'):cmdline+=['--config','http_proxy.host=']ifself.opts.get('debug'):cmdline.append('--debug')cururl=self.currentUrl(False)ifnotcururl:qtlib.InfoMsgBox(_('No URL selected'),_('An URL must be selected for this operation.'),parent=self)returnuser,host,port,folder,passwd,scheme=parseurl(cururl)ifscheme=='https':ifself.repo.ui.configbool('insecurehosts',host):cmdline.append('--insecure')ifuser:cleanurl=hglib.removeauth(cururl)res=hglib.readauthforuri(self.repo.ui,cleanurl,user)ifres:group,auth=resifauth.get('username'):ifqtlib.QuestionMsgBox(_('Redundant authentication info'),_('You have authentication info configured for ''this host and inside this URL. Remove ''authentication info from this URL?'),parent=self):self.setUrl(cleanurl)self.saveclicked()safeurl=self.currentUrl(True)display=' '.join(cmdline+[safeurl]).replace('\n','^M')cmdline.append(cururl)self.repo.incrementBusyCount()self.cmd.run(cmdline,display=display,useproc='p4://'incururl)defoutputHook(self,msg,label):if'\'hg push --new-branch\''inmsg:self.needNewBranch=True#### Workbench toolbar buttons##defincoming(self):ifself.cmd.core.running():self.showMessage.emit(_('sync command already running'))else:self.inclicked()defpull(self):ifself.cmd.core.running():self.showMessage.emit(_('sync command already running'))else:self.pullclicked()defoutgoing(self):ifself.cmd.core.running():self.showMessage.emit(_('sync command already running'))else:self.outclicked()defpush(self,confirm,rev=None,branch=None):ifself.cmd.core.running():self.showMessage.emit(_('sync command already running'))else:self.pushclicked(confirm,rev,branch)defpullBundle(self,bundle,rev):'accept bundle changesets'ifself.cmd.core.running():self.output.emit(_('sync command already running'),'control')returnsave=self.currentUrl(False)orev=self.opts.get('rev')self.setUrl(bundle)ifrevisnotNone:self.opts['rev']=str(rev)self.pullclicked()self.setUrl(save)self.opts['rev']=orev#### Sync dialog buttons##definclicked(self):self.syncStarted.emit()url=self.currentUrl(True)urlu=hglib.tounicode(url)self.showMessage.emit(_('Getting incoming changesets from %s...')%urlu)ifself.embeddedandnoturl.startswith('p4://')and \
notself.opts.get('subrepos'):deffinished(ret,output):ifret==0andos.path.exists(bfile):self.showMessage.emit(_('Found incoming changesets from %s')%urlu)self.incomingBundle.emit(hglib.tounicode(bfile))elifret==1:self.showMessage.emit(_('No incoming changesets from %s')%urlu)else:self.showMessage.emit(_('Incoming from %s aborted, ret %d')%(urlu,ret))bfile=urlforbadcharin(':','*','\\','?','#'):bfile=bfile.replace(badchar,'')bfile=bfile.replace('/','_')bfile=tempfile.mktemp('.hg',bfile+'_',qtlib.gettempdir())self.finishfunc=finishedcmdline=['--repository',self.repo.root,'incoming','--quiet','--bundle',bfile]self.run(cmdline,('force','branch','rev'))else:deffinished(ret,output):ifret==0:self.showMessage.emit(_('Found incoming changesets from %s')%urlu)elifret==1:self.showMessage.emit(_('No incoming changesets from %s')%urlu)else:self.showMessage.emit(_('Incoming from %s aborted, ret %d')%(urlu,ret))self.finishfunc=finishedcmdline=['--repository',self.repo.root,'incoming']self.run(cmdline,('force','branch','rev','subrepos'))defpullclicked(self):self.syncStarted.emit()url=self.currentUrl(True)urlu=hglib.tounicode(url)deffinished(ret,output):ifret==0:self.showMessage.emit(_('Pull from %s completed')%urlu)else:self.showMessage.emit(_('Pull from %s aborted, ret %d')%(urlu,ret))self.pullCompleted.emit()# handle file conflicts during rebaseifself.opts.get('rebase'):ifos.path.exists(self.repo.join('rebasestate')):dlg=rebase.RebaseDialog(self.repo,self)dlg.finished.connect(dlg.deleteLater)dlg.exec_()return# handle file conflicts during updateforroot,path,statusinthgrepo.recursiveMergeStatus(self.repo):ifstatus=='u':qtlib.InfoMsgBox(_('Merge caused file conflicts'),_('File conflicts need to be resolved'))dlg=resolve.ResolveDialog(self.repo,self)dlg.finished.connect(dlg.deleteLater)dlg.exec_()returnself.finishfunc=finishedself.showMessage.emit(_('Pulling from %s...')%urlu)cmdline=['--repository',self.repo.root,'pull','--verbose']uimerge=self.repo.ui.configbool('tortoisehg','autoresolve') \
and'ui.merge=internal:merge'or'ui.merge=internal:fail'ifself.cachedpp=='rebase':cmdline+=['--rebase','--config',uimerge]elifself.cachedpp=='update':cmdline+=['--update','--config',uimerge]elifself.cachedpp=='fetch':cmdline[2]='fetch'self.run(cmdline,('force','branch','rev','bookmark'))defoutclicked(self):self.syncStarted.emit()url=self.currentUrl(True)urlu=hglib.tounicode(url)self.showMessage.emit(_('Finding outgoing changesets to %s...')%urlu)ifself.embeddedandnotself.opts.get('subrepos'):defverifyhash(hash):iflen(hash)!=40:returnFalsebad=[cforcinhashifcnotin'0123456789abcdef']returnnotbaddefoutputnodes(ret,data):ifret==0:nodes=[nfornindata.splitlines()ifverifyhash(n)]ifnodes:self.outgoingNodes.emit(nodes)self.showMessage.emit(_('%d outgoing changesets to %s')%(len(nodes),urlu))elifret==1:self.showMessage.emit(_('No outgoing changesets to %s')%urlu)else:self.showMessage.emit(_('Outgoing to %s aborted, ret %d')%(urlu,ret))self.finishfunc=outputnodescmdline=['--repository',self.repo.root,'outgoing','--quiet','--template','{node}\n']self.run(cmdline,('force','branch','rev'))else:self.finishfunc=Nonecmdline=['--repository',self.repo.root,'outgoing']self.run(cmdline,('force','branch','rev','subrepos'))defp4pending(self):p4url=self.currentUrl(False)deffinished(ret,output):pending={}ifret==0:forlineinoutput.splitlines():ifline.startswith('ignoring hg revision'):continuetry:hashes=line.split(' ')changelist=hashes.pop(0)clnum=int(changelist)iflen(hashes)>1andlen(hashes[0])==1:state=hashes.pop(0)ifstate=='s':changelist=_('%s (submitted)')%changelistelifstate=='p':changelist=_('%s (pending)')%changelistelse:raiseValueErrorpending[changelist]=hashesexcept(ValueError,IndexError):text=_('Unable to parse p4pending output')ifpending:text=_('%d pending changelists found')%len(pending)else:text=_('No pending Perforce changelists')elifretisNone:text=_('Aborted p4pending')else:text=_('Unable to determine pending changesets')self.showMessage.emit(text)ifpending:fromtortoisehg.hgqt.p4pendingimportPerforcePendingdlg=PerforcePending(self.repo,pending,p4url,self)dlg.showMessage.connect(self.showMessage)dlg.output.connect(self.output)dlg.makeLogVisible.connect(self.makeLogVisible)dlg.exec_()self.finishfunc=finishedself.showMessage.emit(_('Perforce pending...'))self.run(['--repository',self.repo.root,'p4pending','--verbose'],())defpushclicked(self,confirm,rev=None,branch=None):validopts=('force','new-branch','branch','rev','bookmark')self.syncStarted.emit()url=self.currentUrl(True)urlu=hglib.tounicode(url)if(nothg.islocal(self.currentUrl(False))andconfirm and not self.targetcheckbox.isChecked()):
r = qtlib.QuestionMsgBox(_('Confirm Push to remote Repository'),
_('Push to remote repository\n%s\n?')
- % urlu)
+ % urlu, parent=self)
if not r:
self.showMessage.emit(_('Push to %s aborted') % urlu)
self.pushCompleted.emit()
returnself.showMessage.emit(_('Pushing to %s...')%urlu)deffinished(ret,output):ifret==0:self.showMessage.emit(_('Push to %s completed')%urlu)else:self.showMessage.emit(_('Push to %s aborted, ret %d')%(urlu,ret))ifself.needNewBranch:r=qtlib.QuestionMsgBox(_('Confirm New Branch'),_('One or more of the changesets that you ' 'are attempting to push involve the '
'creation of a new branch. Do you want '
'to create a new branch in the remote '
- 'repository?'))
+ 'repository?'), parent=self)
if r:
cmdline = self.lastcmdline
cmdline.extend(['--new-branch'])
self.run(cmdline,validopts)returnself.pushCompleted.emit()self.finishfunc=finishedcmdline=['--repository',self.repo.root,'push']ifrev:cmdline.extend(['--rev',str(rev)])ifbranch:cmdline.extend(['--branch',branch])self.needNewBranch=Falseself.run(cmdline,validopts)defpostpullclicked(self):dlg=PostPullDialog(self.repo,self)dlg.setWindowFlags(Qt.Sheet)dlg.setWindowModality(Qt.WindowModal)dlg.exec_()defemailclicked(self):self.showMessage.emit(_('Determining outgoing changesets to email...'))defoutputnodes(ret,data):ifret==0:nodes=[nfornindata.splitlines()iflen(n)==40]self.showMessage.emit(_('%d outgoing changesets')%len(nodes))try:outgoingrevs=[cmdline[cmdline.index('--rev')+1]]exceptValueError:outgoingrevs=Nonefromtortoisehg.hgqtimportrunas_run_run.email(ui.ui(),repo=self.repo,rev=nodes,outgoing=True,outgoingrevs=outgoingrevs)elifret==1:self.showMessage.emit(_('No outgoing changesets'))else:self.showMessage.emit(_('Outgoing aborted, ret %d')%ret)self.finishfunc=outputnodescmdline=['--repository',self.repo.root,'outgoing','--quiet','--template','{node}\n']self.run(cmdline,('force','branch','rev'))defunbundle(self):caption=_("Select bundle file")_FILE_FILTER="%s"%_("Bundle files (*.hg)")bundlefile=QFileDialog.getOpenFileName(parent=self,caption=caption,directory=self.repo.root,filter=_FILE_FILTER)ifbundlefile:# Select the "Local" schemeself.schemecombo.setCurrentIndex(0)# Set the pull source to the selected bundle fileself.pathentry.setText(bundlefile)# Execute the incomming command, which will show the revisions in# the bundle, and let the user accept or reject themself.inclicked()@pyqtSlot(QString)defremoveAlias(self,alias):alias=hglib.fromunicode(alias)fn=self.repo.join('hgrc')fn,cfg=hgrcutil.loadIniFile([fn],self)ifnothasattr(cfg,'write'):qtlib.WarningMsgBox(_('Unable to remove URL'),_('Iniparse must be installed.'),parent=self)returniffnisNone:returnifaliasincfg['paths']:delcfg['paths'][alias]self.repo.incrementBusyCount()try:wconfig.writefile(cfg,fn)exceptEnvironmentError,e:qtlib.WarningMsgBox(_('Unable to write configuration file'),hglib.tounicode(str(e)),parent=self)self.repo.decrementBusyCount()classPostPullDialog(QDialog):def__init__(self,repo,parent):super(PostPullDialog,self).__init__(parent)self.repo=repolayout=QVBoxLayout()self.setLayout(layout)self.setWindowTitle(_('Post Pull Behavior'))self.setWindowFlags(self.windowFlags()&~Qt.WindowContextHelpButtonHint)lbl=QLabel(_('Select post-pull operation for this repository'))layout.addWidget(lbl)self.none=QRadioButton(_('None - simply pull changesets'))self.update=QRadioButton(_('Update - pull, then try to update'))layout.addWidget(self.none)layout.addWidget(self.update)if'fetch'inrepo.extensions()orrepo.postpull=='fetch':if'fetch'inrepo.extensions():btntxt=_('Fetch - use fetch (auto merge pulled changes)')else:btntxt=_('Fetch - use fetch extension (fetch is not active!)')self.fetch=QRadioButton(btntxt)layout.addWidget(self.fetch)else:self.fetch=Noneif'rebase'inrepo.extensions()orrepo.postpull=='rebase':if'rebase'inrepo.extensions():btntxt=_('Rebase - rebase local commits above pulled changes')else:btntxt=_('Rebase - use rebase extension (rebase is not active!)')self.rebase=QRadioButton(btntxt)layout.addWidget(self.rebase)self.none.setChecked(True)ifrepo.postpull=='update':self.update.setChecked(True)elifrepo.postpull=='fetch':self.fetch.setChecked(True)elifrepo.postpull=='rebase':self.rebase.setChecked(True)self.autoresolve_chk=QCheckBox(_('Automatically resolve merge conflicts ''where possible'))self.autoresolve_chk.setChecked(repo.ui.configbool('tortoisehg','autoresolve',False))layout.addWidget(self.autoresolve_chk)cfglabel=QLabel(_('<a href="config">Launch settings tool...</a>'))cfglabel.linkActivated.connect(self.linkactivated)layout.addWidget(cfglabel)BB=QDialogButtonBoxbb=QDialogButtonBox(BB.Save|BB.Cancel)bb.accepted.connect(self.accept)bb.rejected.connect(self.reject)self.bb=bblayout.addWidget(bb)deflinkactivated(self,command):ifcommand=='config':fromtortoisehg.hgqt.settingsimportSettingsDialogsd=SettingsDialog(configrepo=False,focus='tortoisehg.postpull',parent=self,root=self.repo.root)sd.exec_()defgetValue(self):ifself.none.isChecked():return'none'elifself.update.isChecked():return'update'elif(self.fetchandself.fetch.isChecked()):return'fetch'else:return'rebase'defaccept(self):path=self.repo.join('hgrc')fn,cfg=hgrcutil.loadIniFile([path],self)ifnothasattr(cfg,'write'):qtlib.WarningMsgBox(_('Unable to save post pull operation'),_('Iniparse must be installed.'),parent=self)returniffnisNone:returnself.repo.incrementBusyCount()try:cfg.set('tortoisehg','postpull',self.getValue())cfg.set('tortoisehg','autoresolve',self.autoresolve_chk.isChecked())wconfig.writefile(cfg,fn)exceptEnvironmentError,e:qtlib.WarningMsgBox(_('Unable to write configuration file'),hglib.tounicode(str(e)),parent=self)self.repo.decrementBusyCount()super(PostPullDialog,self).accept()defreject(self):super(PostPullDialog,self).reject()classSaveDialog(QDialog):def__init__(self,repo,alias,origurl,safeurl,parent):super(SaveDialog,self).__init__(parent)self.setWindowTitle(_('Save Path'))self.setWindowFlags(self.windowFlags()&~Qt.WindowContextHelpButtonHint)self.repo=repoself.origurl=origurlself.setLayout(QFormLayout(fieldGrowthPolicy=QFormLayout.ExpandingFieldsGrow))self.aliasentry=QLineEdit(hglib.tounicode(alias))self.aliasentry.selectAll()self.layout().addRow(_('Alias'),self.aliasentry)self.urllabel=QLabel(hglib.tounicode(safeurl))self.layout().addRow(_('URL'),self.urllabel)user,host,port,folder,passwd,scheme=parseurl(origurl)if(userorpasswd)andschemein('http','https'):cleanurl=hglib.removeauth(origurl)defshowurl(showclean):newurl=showcleanandcleanurlorsafeurlself.urllabel.setText(hglib.tounicode(newurl))self.cleanurl=cleanurlself.clearcb=QCheckBox(_('Remove authentication data from URL'))self.clearcb.setToolTip(_('User authentication data should be associated with the ''hostname using the security dialog.'))self.clearcb.toggled.connect(showurl)self.clearcb.setChecked(True)self.layout().addRow(self.clearcb)else:self.clearcb=NoneBB=QDialogButtonBoxbb=QDialogButtonBox(BB.Save|BB.Cancel)bb.accepted.connect(self.accept)bb.rejected.connect(self.reject)bb.button(BB.Save).setAutoDefault(True)self.bb=bbself.layout().addRow(None,bb)QTimer.singleShot(0,lambda:self.aliasentry.setFocus())defaccept(self):fn=self.repo.join('hgrc')fn,cfg=hgrcutil.loadIniFile([fn],self)ifnothasattr(cfg,'write'):qtlib.WarningMsgBox(_('Unable to save an URL'),_('Iniparse must be installed.'),parent=self)returniffnisNone:returnalias=hglib.fromunicode(self.aliasentry.text())ifself.clearcbandself.clearcb.isChecked():path=self.cleanurlelse: path = self.origurl
if alias in cfg['paths']:
if not qtlib.QuestionMsgBox(_('Confirm URL replace'),
- _('%s already exists, replace URL?') % alias):
+ _('%s already exists, replace URL?') % alias, parent=self):
return
cfg.set('paths', alias, path)
self.repo.incrementBusyCount()
try:wconfig.writefile(cfg,fn)exceptEnvironmentError,e:qtlib.WarningMsgBox(_('Unable to write configuration file'),hglib.tounicode(str(e)),parent=self)self.repo.decrementBusyCount()super(SaveDialog,self).accept()defreject(self):super(SaveDialog,self).reject()classSecureDialog(QDialog):def__init__(self,repo,origurl,parent):super(SecureDialog,self).__init__(parent)defgenfingerprint():try:pem=ssl.get_server_certificate((host,port))der=ssl.PEM_cert_to_DER_cert(pem)exceptException,e:qtlib.WarningMsgBox(_('Certificate Query Error'),hglib.tounicode(str(e)),parent=self)returnhash=util.sha1(der).hexdigest()pretty=":".join([hash[x:x+2]forxinxrange(0,len(hash),2)])le.setText(pretty)user,host,port,folder,passwd,scheme=parseurl(origurl)ifportisNone:port=443else:port=int(port)uhost=hglib.tounicode(host)self.setWindowTitle(_('Security: ')+uhost)self.setWindowFlags(self.windowFlags()& \
~Qt.WindowContextHelpButtonHint)# if the already user has an [auth] configuration for this URL, use itcleanurl=hglib.removeauth(origurl)res=hglib.readauthforuri(repo.ui,cleanurl,user)ifres:self.alias,auth=reselse:self.alias,auth=host,{}self.repo=repoself.host=hostifcleanurl.startswith('svn+https://'):self.schemes='svn+https'else:self.schemes=Noneself.setLayout(QVBoxLayout())self.layout().addWidget(QLabel(_('<b>Host:</b> %s')%uhost))securebox=QGroupBox(_('Secure HTTPS Connection'))self.layout().addWidget(securebox)vbox=QVBoxLayout()securebox.setLayout(vbox)self.layout().addWidget(securebox)self.cacertradio=QRadioButton(_('Verify with Certificate Authority certificates (best)'))self.fprintradio=QRadioButton(_('Verify with stored host fingerprint (good)'))self.insecureradio=QRadioButton(_('No host validation, but still encrypted (bad)'))hbox=QHBoxLayout()fprint=repo.ui.config('hostfingerprints',host,'')self.fprintentry=le=QLineEdit(fprint)self.fprintradio.toggled.connect(self.fprintentry.setEnabled)self.fprintentry.setEnabled(False)ifhasattr(le,'setPlaceholderText'):# Qt >= 4.7le.setPlaceholderText(_('### host certificate fingerprint ###'))hbox.addWidget(le)try:importssl# Python 2.6 or backport for 2.5qb=QPushButton(_('Query'))qb.clicked.connect(genfingerprint)qb.setEnabled(False)self.fprintradio.toggled.connect(qb.setEnabled)hbox.addWidget(qb)exceptImportError:passvbox.addWidget(self.cacertradio)vbox.addWidget(self.fprintradio)vbox.addLayout(hbox)vbox.addWidget(self.insecureradio)self.cacertradio.setEnabled(bool(repo.ui.config('web','cacerts')))self.cacertradio.setChecked(True)# defaultiffprint:self.fprintradio.setChecked(True)elifrepo.ui.config('insecurehosts',host):self.insecureradio.setChecked(True)authbox=QGroupBox(_('User Authentication'))form=QFormLayout()authbox.setLayout(form)self.layout().addWidget(authbox)self.userentry=QLineEdit(userorauth.get('username',''))self.userentry.setToolTip(_('''Optional. Username to authenticate with. If not given, and the remotesite requires basic or digest authentication, the user will be prompted forit. Environment variables are expanded in the username letting you dofoo.username = $USER.'''))form.addRow(_('Username'),self.userentry)self.pwentry=QLineEdit(passwdorauth.get('password',''))self.pwentry.setEchoMode(QLineEdit.Password)self.pwentry.setToolTip(_('''Optional. Password to authenticate with. If not given, and the remotesite requires basic or digest authentication, the user will be prompted forit.'''))form.addRow(_('Password'),self.pwentry)if'mercurial_keyring'inrepo.extensions():self.pwentry.clear()self.pwentry.setEnabled(False)self.pwentry.setToolTip(_('Mercurial keyring extension is enabled. ''Passwords will be stored in a platform-native ''secure method.'))self.keyentry=QLineEdit(auth.get('key',''))self.keyentry.setToolTip(_('''Optional. PEM encoded client certificate key file. Environment variablesare expanded in the filename.'''))form.addRow(_('User Certificate Key File'),self.keyentry)self.chainentry=QLineEdit(auth.get('cert',''))self.chainentry.setToolTip(_('''Optional. PEM encoded client certificate chain file. Environment variablesare expanded in the filename.'''))form.addRow(_('User Certificate Chain File'),self.chainentry)BB=QDialogButtonBoxbb=QDialogButtonBox(BB.Help|BB.Save|BB.Cancel)bb.rejected.connect(self.reject)bb.accepted.connect(self.accept)bb.helpRequested.connect(self.keyringHelp)self.bb=bbself.layout().addWidget(bb)self.userentry.selectAll()QTimer.singleShot(0,lambda:self.userentry.setFocus())defkeyringHelp(self):qtlib.openhelpcontents('sync.html#security')defaccept(self):path=hglib.user_rcpath()fn,cfg=hgrcutil.loadIniFile(path,self)ifnothasattr(cfg,'write'):qtlib.WarningMsgBox(_('Unable to save authentication'),_('Iniparse must be installed.'),parent=self)returniffnisNone:returndefsetorclear(section,item,value):ifvalue:cfg.set(section,item,value)elifnotvalueanditemincfg[section]:delcfg[section][item]ifself.cacertradio.isChecked():fprint=Noneinsecure=Noneelifself.fprintradio.isChecked():fprint=hglib.fromunicode(self.fprintentry.text())insecure=Noneelse:fprint=Noneinsecure='1'setorclear('hostfingerprints',self.host,fprint)setorclear('insecurehosts',self.host,insecure)username=hglib.fromunicode(self.userentry.text())password=hglib.fromunicode(self.pwentry.text())key=hglib.fromunicode(self.keyentry.text())chain=hglib.fromunicode(self.chainentry.text())cfg.set('auth',self.alias+'.prefix',self.host)setorclear('auth',self.alias+'.username',username)setorclear('auth',self.alias+'.password',password)setorclear('auth',self.alias+'.key',key)setorclear('auth',self.alias+'.cert',chain)setorclear('auth',self.alias+'.schemes',self.schemes)self.repo.incrementBusyCount()try:wconfig.writefile(cfg,fn)exceptEnvironmentError,e:qtlib.WarningMsgBox(_('Unable to write configuration file'),hglib.tounicode(str(e)),parent=self)self.repo.decrementBusyCount()super(SecureDialog,self).accept()defreject(self):super(SecureDialog,self).reject()classPathsTree(QTreeView):removeAlias=pyqtSignal(QString)menuRequest=pyqtSignal(QPoint,QString,QString,bool)def__init__(self,parent,editable):QTreeView.__init__(self,parent)self.setSelectionMode(QTreeView.SingleSelection)self.editable=editabledefcontextMenuEvent(self,event):forindexinself.selectedRows():alias=index.data(Qt.DisplayRole).toString()url=index.sibling(index.row(),1).data(Qt.DisplayRole).toString()self.menuRequest.emit(event.globalPos(),url,alias,self.editable)returndefkeyPressEvent(self,event):ifself.editableandevent.matches(QKeySequence.Delete):self.deleteSelected()else:returnsuper(PathsTree,self).keyPressEvent(event)defdeleteSelected(self):forindexinself.selectedRows():alias=index.data(Qt.DisplayRole).toString()r=qtlib.QuestionMsgBox(_('Confirm path delete'),_('Delete %s from your repo configuration file?')%alias,parent=self)ifr:self.removeAlias.emit(alias)defselectedUrls(self):forindexinself.selectedRows():yieldindex.sibling(index.row(),1).data(Qt.DisplayRole).toString()defdragObject(self):urls=[]forurlinself.selectedUrls():u=QUrl()u.setPath(url)urls.append(u)ifurls:d=QDrag(self)m=QMimeData()m.setUrls(urls)d.setMimeData(m)d.start(Qt.CopyAction)defmousePressEvent(self,event):self.pressPos=event.pos()self.pressTime=QTime.currentTime()returnsuper(PathsTree,self).mousePressEvent(event)defmouseMoveEvent(self,event):d=event.pos()-self.pressPosifd.manhattanLength()<QApplication.startDragDistance():returnQTreeView.mouseMoveEvent(self,event)elapsed=self.pressTime.msecsTo(QTime.currentTime())ifelapsed<QApplication.startDragTime():returnsuper(PathsTree,self).mouseMoveEvent(event)self.dragObject()returnsuper(PathsTree,self).mouseMoveEvent(event)defselectedRows(self):returnself.selectionModel().selectedRows()classPathsModel(QAbstractTableModel):def__init__(self,pathlist,parent=None):QAbstractTableModel.__init__(self,parent)self.headers=(_('Alias'),_('URL'))self.rows=[]foralias,pathinpathlist:safepath=hglib.hidepassword(path)ualias=hglib.tounicode(alias)usafepath=hglib.tounicode(safepath)self.rows.append([ualias,usafepath,path])defrowCount(self,parent):ifparent.isValid():return0# no childreturnlen(self.rows)defcolumnCount(self,parent):ifparent.isValid():return0# no childreturnlen(self.headers)defdata(self,index,role):ifnotindex.isValid():returnQVariant()ifrole==Qt.DisplayRole:returnQVariant(self.rows[index.row()][index.column()])returnQVariant()defheaderData(self,col,orientation,role):ifrole!=Qt.DisplayRoleororientation!=Qt.Horizontal:returnQVariant()else:returnQVariant(self.headers[col])defflags(self,index):flags=Qt.ItemIsSelectable|Qt.ItemIsEnabled|Qt.ItemIsDragEnabledreturnflagsdefrealUrl(self,index):returnself.rows[index.row()][2]classOptionsDialog(QDialog):'Utility dialog for configuring uncommon options'def__init__(self,opts,parent):QDialog.__init__(self,parent)self.setWindowTitle(_('%s - sync options')%parent.repo.displayname)self.repo=parent.repolayout=QFormLayout()self.setLayout(layout)self.newbranchcb=QCheckBox(_('Allow push of a new branch (--new-branch)'))self.newbranchcb.setChecked(opts.get('new-branch',False))layout.addRow(self.newbranchcb,None)self.forcecb=QCheckBox(_('Force push or pull (override safety checks, --force)'))self.forcecb.setChecked(opts.get('force',False))layout.addRow(self.forcecb,None)self.subrepocb=QCheckBox(_('Recurse into subrepositories')+u' (--subrepos)')self.subrepocb.setChecked(opts.get('subrepos',False))layout.addRow(self.subrepocb,None)self.noproxycb=QCheckBox(_('Temporarily disable configured HTTP proxy'))self.noproxycb.setChecked(opts.get('noproxy',False))layout.addRow(self.noproxycb,None)proxy=self.repo.ui.config('http_proxy','host')self.noproxycb.setEnabled(bool(proxy))self.debugcb=QCheckBox(_('Emit debugging output (--debug)'))self.debugcb.setChecked(opts.get('debug',False))layout.addRow(self.debugcb,None)lbl=QLabel(_('Remote command:'))self.remotele=QLineEdit()ifopts.get('remotecmd'):self.remotele.setText(hglib.tounicode(opts['remotecmd']))layout.addRow(lbl,self.remotele)BB=QDialogButtonBoxbb=QDialogButtonBox(BB.Ok|BB.Cancel)bb.accepted.connect(self.accept)bb.rejected.connect(self.reject)self.bb=bblayout.addWidget(bb)defaccept(self):outopts={}forname,lein(('remotecmd',self.remotele),):outopts[name]=hglib.fromunicode(le.text()).strip()outopts['subrepos']=self.subrepocb.isChecked()outopts['force']=self.forcecb.isChecked()outopts['new-branch']=self.newbranchcb.isChecked()outopts['noproxy']=self.noproxycb.isChecked()outopts['debug']=self.debugcb.isChecked()self.outopts=outoptsQDialog.accept(self)defrun(ui,*pats,**opts):repo=thgrepo.repository(ui,path=paths.find_root())returnSyncWidget(repo,None,addmargin=True,**opts)
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.