def onCompletion(self): self.qui.progress_bar.hide() self.qui.progress_label.hide() output = self.cmd.core.rawoutput() saved = 'saved:' in output published = 'published:' in output if (saved or published): if saved: url = output.split('saved: ').pop().strip() msg = _('Review draft posted to %s\n') % url else: url = output.split('published: ').pop().strip() msg = _('Review published to %s\n') % url QDesktopServices.openUrl(QUrl(url)) qtlib.InfoMsgBox(_('Review Board'), _('Success'), msg, parent=self) else: error = output.split('abort: ').pop().strip() if error[:29] == "HTTP Error: basic auth failed": if self.passwordPrompt(): self.accept() else: self.qui.post_review_button.setEnabled(True) self.qui.close_button.setEnabled(True) return else: qtlib.ErrorMsgBox(_('Review Board'), _('Error'), error) self.writeSettings() super(PostReviewDialog, self).accept()
def accept(self): for root, path, status in thgrepo.recursiveMergeStatus(self.repo): if status == 'u': qtlib.InfoMsgBox(_('Merge caused file conflicts'), _('File conflicts need to be resolved')) dlg = resolve.ResolveDialog(self._repoagent, self) dlg.finished.connect(dlg.deleteLater) dlg.exec_() break super(UpdateDialog, self).accept()
def run(ui, *pats, **opts): from tortoisehg.util import paths repo = thgrepo.repository(ui, path=paths.find_root()) if os.path.exists(repo.join('rebasestate')): qtlib.InfoMsgBox(_('Rebase already in progress'), _('Resuming rebase already in progress')) elif not opts['source'] or not opts['dest']: qtlib.ErrorMsgBox(_('Abort'), _('You must provide source and dest arguments')) import sys; sys.exit() return RebaseDialog(repo, None, **opts)
def run(ui, *pats, **opts): from tortoisehg.util import paths rev = opts.get('rev') or None if not rev and len(pats): rev = pats[0] if not rev: import sys qtlib.InfoMsgBox(_('Unable to merge'), _('Merge revision not specified or not found')) sys.exit() repo = thgrepo.repository(ui, path=paths.find_root()) return MergeDialog(rev, repo, None)
def rebase(ui, repoagent, *pats, **opts): """rebase dialog""" from tortoisehg.hgqt import rebase as rebasemod repo = repoagent.rawRepo() if os.path.exists(repo.join('rebasestate')): # TODO: move info dialog into RebaseDialog if possible qtlib.InfoMsgBox( hglib.tounicode(_('Rebase already in progress')), hglib.tounicode(_('Resuming rebase already in ' 'progress'))) elif not opts['source'] or not opts['dest']: raise util.Abort(_('You must provide source and dest arguments')) return rebasemod.RebaseDialog(repoagent, None, **opts)
def run(ui, *revs, **opts): from tortoisehg.util import paths repo = thgrepo.repository(ui, path=paths.find_root()) revs = list(revs) revs.extend(opts['rev']) if os.path.exists(repo.join('graftstate')): qtlib.InfoMsgBox(_('Graft already in progress'), _('Resuming graft already in progress')) elif not revs: qtlib.ErrorMsgBox(_('Abort'), _('You must provide revisions to graft')) import sys; sys.exit() return GraftDialog(repo, None, source=revs)
def getVdiffFiles(self, tree): paths = self.getSelectedPaths(tree) if not paths: return [] files, sub = [], False for root, wfile in paths: if root == self.repo.root: files.append(wfile) else: sub = True if sub: qtlib.InfoMsgBox(_('Unable to show subrepository files'), _('Visual diffs are not supported for files in ' 'subrepositories. They will not be shown.')) return files
def removeFile(self, wfile): repo = self.repo ctx = self.ctx if isinstance(ctx, patchctx): repo.thgbackup(ctx._path) fp = util.atomictempfile(ctx._path, 'wb') try: if ctx._ph.comments: fp.write('\n'.join(ctx._ph.comments)) fp.write('\n\n') for file in ctx._fileorder: if file == wfile: continue for chunk in ctx._files[file]: chunk.write(fp) fp.close() finally: del fp ctx.invalidate() else: fullpath = repo.wjoin(wfile) repo.thgbackup(fullpath) wasadded = wfile in repo[None].added() try: commands.revert(repo.ui, repo, fullpath, rev='.', no_backup=True) if wasadded and os.path.exists(fullpath): os.unlink(fullpath) except EnvironmentError: qtlib.InfoMsgBox( _("Unable to remove"), _("Unable to remove file %s,\n" "permission denied") % hglib.tounicode(wfile)) self.fileModified.emit()
def initializePage(self): if self.layout(): return self.setTitle(_('Prepare to backout')) self.setSubTitle( _('Verify backout revision and ensure your working ' 'directory is clean.')) self.setLayout(QVBoxLayout()) self.groups = qtlib.WidgetGroups() repo = self.repo try: bctx = repo[self.wizard().backoutrev] pctx = repo['.'] except error.RepoLookupError: qtlib.InfoMsgBox(_('Unable to backout'), _('Backout revision not found')) QTimer.singleShot(0, self.wizard().close) return if pctx == bctx: lbl = _('Backing out a parent revision is a single step operation') self.layout().addWidget(QLabel(u'<b>%s</b>' % lbl)) self.wizard().parentbackout = True op1, op2 = repo.dirstate.parents() if op1 is None: qtlib.InfoMsgBox(_('Unable to backout'), _('Backout requires a parent revision')) QTimer.singleShot(0, self.wizard().close) return a = repo.changelog.ancestor(op1, bctx.node()) if a != bctx.node(): qtlib.InfoMsgBox(_('Unable to backout'), _('Cannot backout change on a different branch')) QTimer.singleShot(0, self.wizard().close) ## backout revision style = csinfo.panelstyle(contents=csinfo.PANEL_DEFAULT) create = csinfo.factory(repo, None, style, withupdate=True) sep = qtlib.LabeledSeparator(_('Backout revision')) self.layout().addWidget(sep) backoutCsInfo = create(bctx.rev()) self.layout().addWidget(backoutCsInfo) ## current revision contents = ('ishead', ) + csinfo.PANEL_DEFAULT style = csinfo.panelstyle(contents=contents) def markup_func(widget, item, value): if item == 'ishead' and value is False: text = _('Not a head, backout will create a new head!') return qtlib.markup(text, fg='red', weight='bold') raise csinfo.UnknownItem(item) custom = csinfo.custom(markup=markup_func) create = csinfo.factory(repo, custom, style, withupdate=True) sep = qtlib.LabeledSeparator(_('Current local revision')) self.layout().addWidget(sep) localCsInfo = create(pctx.rev()) self.layout().addWidget(localCsInfo) self.localCsInfo = localCsInfo ## Merge revision backout handling if len(bctx.parents()) > 1: # Show two radio buttons letting the user which merge revision # parent to backout to p1rev = bctx.p1().rev() p2rev = bctx.p2().rev() def setBackoutMergeParentRev(rev): self.wizard().backoutmergeparentrev = rev setBackoutMergeParentRev(p1rev) sep = qtlib.LabeledSeparator(_('Merge parent to backout to')) self.layout().addWidget(sep) self.layout().addWidget( QLabel( _('To backout a <b>merge</b> revision you must select which ' 'parent to backout to ' '(i.e. whose changes will be <i>kept</i>)'))) self.actionFirstParent = QRadioButton( _('First Parent: revision %s (%s)') \ % (p1rev, str(bctx.p1())), self) self.actionFirstParent.setCheckable(True) self.actionFirstParent.setChecked(True) self.actionFirstParent.setShortcut('CTRL+1') self.actionFirstParent.setToolTip( _('Backout to the first parent of the merge revision')) self.actionFirstParent.clicked.connect( lambda: setBackoutMergeParentRev(p1rev)) self.actionSecondParent = QRadioButton( _('Second Parent: revision %s (%s)') % (p2rev, str(bctx.p2())), self) self.actionSecondParent.setCheckable(True) self.actionSecondParent.setShortcut('CTRL+2') self.actionSecondParent.setToolTip( _('Backout to the second parent of the merge revision')) self.actionSecondParent.clicked.connect( lambda: setBackoutMergeParentRev(p2rev)) self.layout().addWidget(self.actionFirstParent) self.layout().addWidget(self.actionSecondParent) ## working directory status sep = qtlib.LabeledSeparator(_('Working directory status')) self.layout().addWidget(sep) wdbox = QHBoxLayout() self.layout().addLayout(wdbox) self.wd_status = qtlib.StatusLabel() self.wd_status.set_status(_('Checking...')) wdbox.addWidget(self.wd_status) wd_prog = QProgressBar() wd_prog.setMaximum(0) wd_prog.setTextVisible(False) self.groups.add(wd_prog, 'prog') wdbox.addWidget(wd_prog, 1) text = _( 'Before backout, you must <a href="commit"><b>commit</b></a>, ' '<a href="shelve"><b>shelve</b></a> to patch, ' 'or <a href="discard"><b>discard</b></a> changes.') wd_text = QLabel(text) wd_text.setWordWrap(True) wd_text.linkActivated.connect(self.onLinkActivated) self.wd_text = wd_text self.groups.add(wd_text, 'dirty') self.layout().addWidget(wd_text) ## auto-resolve autoresolve_chk = QCheckBox( _('Automatically resolve merge conflicts ' 'where possible')) autoresolve_chk.setChecked( repo.ui.configbool('tortoisehg', 'autoresolve', False)) self.registerField('autoresolve', autoresolve_chk) self.layout().addWidget(autoresolve_chk) self.autoresolve_chk = autoresolve_chk self.groups.set_visible(False, 'dirty')
def mergeChunks(self, wfile, chunks): def isAorR(header): for line in header: if line.startswith('--- /dev/null'): return True if line.startswith('+++ /dev/null'): return True return False repo = self.repo ctx = self.ctx if isinstance(ctx, patchctx): if wfile in ctx._files: patchchunks = ctx._files[wfile] if isAorR(chunks[0].header) or isAorR(patchchunks[0].header): qtlib.InfoMsgBox( _('Unable to merge chunks'), _('Add or remove patches must be merged ' 'in the working directory')) return False # merge new chunks into existing chunks, sorting on start line newchunks = [chunks[0]] pidx = nidx = 1 while pidx < len(patchchunks) or nidx < len(chunks): if pidx == len(patchchunks): newchunks.append(chunks[nidx]) nidx += 1 elif nidx == len(chunks): newchunks.append(patchchunks[pidx]) pidx += 1 elif chunks[nidx].fromline < patchchunks[pidx].fromline: newchunks.append(chunks[nidx]) nidx += 1 else: newchunks.append(patchchunks[pidx]) pidx += 1 ctx._files[wfile] = newchunks else: # add file to patch ctx._files[wfile] = chunks ctx._fileorder.append(wfile) repo.thgbackup(ctx._path) fp = util.atomictempfile(ctx._path, 'wb') try: if ctx._ph.comments: fp.write('\n'.join(ctx._ph.comments)) fp.write('\n\n') for file in ctx._fileorder: for chunk in ctx._files[file]: chunk.write(fp) fp.close() ctx.invalidate() self.fileModified.emit() return True finally: del fp else: # Apply chunks to wfile repo.thgbackup(repo.wjoin(wfile)) fp = cStringIO.StringIO() for c in chunks: c.write(fp) fp.seek(0) wlock = repo.wlock() try: return self.runPatcher(fp, wfile, True) finally: wlock.release()
qtlib.ErrorMsgBox(_('Error executing init'), _('Error when creating repository'), traceback.format_exc()) return False # Create the .hg* file, mainly to workaround # Explorer's problem in creating files with a name # beginning with a dot. if (self.add_files_chk.isChecked() and os.path.exists(os.path.sep.join([dest, '.hg']))): hgignore = os.path.join(dest, '.hgignore') if not os.path.exists(hgignore): try: open(hgignore, 'wb') except: pass if self.run_wb_chk.isChecked(): # TODO: implement by using signal-slot if possible from tortoisehg.hgqt import run run.qtrun.showRepoInWorkbench(udest) else: if not self.parent(): qtlib.InfoMsgBox(_('Init'), _('<p>Repository successfully created at</p><p>%s</p>') % udest) self.accept() def reject(self): super(InitDialog, self).reject()
def initializePage(self): if self.layout(): return self.setTitle(_('Prepare to merge')) self.setSubTitle( _('Verify merge targets and ensure your working ' 'directory is clean.')) self.setLayout(QVBoxLayout()) repo = self.repo contents = ('ishead', ) + csinfo.PANEL_DEFAULT style = csinfo.panelstyle(contents=contents) def markup_func(widget, item, value): if item == 'ishead' and value is False: text = _('Not a head revision!') return qtlib.markup(text, fg='red', weight='bold') raise csinfo.UnknownItem(item) custom = csinfo.custom(markup=markup_func) create = csinfo.factory(repo, custom, style, withupdate=True) ## merge target other_sep = qtlib.LabeledSeparator(_('Merge from (other revision)')) self.layout().addWidget(other_sep) try: otherCsInfo = create(self.wizard().otherrev) self.layout().addWidget(otherCsInfo) self.otherCsInfo = otherCsInfo except error.RepoLookupError: qtlib.InfoMsgBox(_('Unable to merge'), _('Merge revision not specified or not found')) QTimer.singleShot(0, self.wizard().close) ## current revision local_sep = qtlib.LabeledSeparator(_('Merge to (working directory)')) self.layout().addWidget(local_sep) localCsInfo = create(self.wizard().localrev) self.layout().addWidget(localCsInfo) self.localCsInfo = localCsInfo ## working directory status wd_sep = qtlib.LabeledSeparator(_('Working directory status')) self.layout().addWidget(wd_sep) self.groups = qtlib.WidgetGroups() wdbox = QHBoxLayout() self.layout().addLayout(wdbox) self.wd_status = qtlib.StatusLabel() self.wd_status.set_status(_('Checking...')) wdbox.addWidget(self.wd_status) wd_prog = QProgressBar() wd_prog.setMaximum(0) wd_prog.setTextVisible(False) self.groups.add(wd_prog, 'prog') wdbox.addWidget(wd_prog, 1) wd_merged = QLabel( _('The working directory is already <b>merged</b>. ' '<a href="skip"><b>Continue</b></a> or ' '<a href="discard"><b>discard</b></a> existing ' 'merge.')) wd_merged.linkActivated.connect(self.onLinkActivated) wd_merged.setWordWrap(True) self.groups.add(wd_merged, 'merged') self.layout().addWidget(wd_merged) text = _( 'Before merging, you must <a href="commit"><b>commit</b></a>, ' '<a href="shelve"><b>shelve</b></a> to patch, ' 'or <a href="discard"><b>discard</b></a> changes.') wd_text = QLabel(text) wd_text.setWordWrap(True) wd_text.linkActivated.connect(self.onLinkActivated) self.wd_text = wd_text self.groups.add(wd_text, 'dirty') self.layout().addWidget(wd_text) wdbox = QHBoxLayout() self.layout().addLayout(wdbox) wd_alt = QLabel(_('Or use:')) self.groups.add(wd_alt, 'dirty') wdbox.addWidget(wd_alt) force_chk = QCheckBox( _('Force a merge with outstanding changes ' '(-f/--force)')) force_chk.toggled.connect(lambda c: self.completeChanged.emit()) self.registerField('force', force_chk) self.groups.add(force_chk, 'dirty') wdbox.addWidget(force_chk) ### options expander = qtlib.ExpanderLabel(_('Options'), False) expander.expanded.connect(self.toggleShowOptions) self.layout().addWidget(expander) self.expander = expander ### discard option discard_chk = QCheckBox( _('Discard all changes from merge target ' '(other) revision')) self.registerField('discard', discard_chk) self.layout().addWidget(discard_chk) self.discard_chk = discard_chk ## auto-resolve autoresolve_chk = QCheckBox( _('Automatically resolve merge conflicts ' 'where possible')) autoresolve_chk.setChecked( repo.ui.configbool('tortoisehg', 'autoresolve', False)) self.registerField('autoresolve', autoresolve_chk) self.layout().addWidget(autoresolve_chk) self.autoresolve_chk = autoresolve_chk self.groups.set_visible(False, 'dirty') self.groups.set_visible(False, 'merged') self.toggleShowOptions(self.expander.is_expanded())
def addSubrepo(self): 'menu action handler for adding a new subrepository' root = hglib.tounicode(self.selitem.internalPointer().rootpath()) caption = _('Select an existing repository to add as a subrepo') FD = QFileDialog path = unicode( FD.getExistingDirectory(caption=caption, directory=root, options=FD.ShowDirsOnly | FD.ReadOnly)) if path: path = os.path.normpath(path) sroot = paths.find_root(path) root = os.path.normcase(os.path.normpath(root)) if not sroot: qtlib.WarningMsgBox(_('Cannot add subrepository'), _('%s is not a valid repository') % path, parent=self) return elif not os.path.isdir(sroot): qtlib.WarningMsgBox(_('Cannot add subrepository'), _('"%s" is not a folder') % sroot, parent=self) return elif os.path.normcase(sroot) == root: qtlib.WarningMsgBox( _('Cannot add subrepository'), _('A repository cannot be added as a subrepo of itself'), parent=self) return elif root != paths.find_root( os.path.dirname(os.path.normcase(path))): qtlib.WarningMsgBox( _('Cannot add subrepository'), _('The selected folder:<br><br>%s<br><br>' 'is not inside the target repository.<br><br>' 'This may be allowed but is greatly discouraged.<br>' 'If you want to add a non trivial subrepository mapping ' 'you must manually edit the <i>.hgsub</i> file') % root, parent=self) return else: # The selected path is the root of a repository that is inside # the selected repository # Use forward slashes for relative subrepo root paths srelroot = sroot[len(root) + 1:] srelroot = util.pconvert(srelroot) # Is is already on the selected repository substate list? try: repo = hg.repository(ui.ui(), hglib.fromunicode(root)) except: qtlib.WarningMsgBox( _('Cannot open repository'), _('The selected repository:<br><br>%s<br><br>' 'cannot be open!') % root, parent=self) return if hglib.fromunicode(srelroot) in repo['.'].substate: qtlib.WarningMsgBox( _('Subrepository already exists'), _('The selected repository:<br><br>%s<br><br>' 'is already a subrepository of:<br><br>%s<br><br>' 'as: "%s"') % (sroot, root, srelroot), parent=self) return else: # Already a subrepo! # Read the current .hgsub file contents lines = [] hasHgsub = os.path.exists(repo.wjoin('.hgsub')) if hasHgsub: try: fsub = repo.wopener('.hgsub', 'r') lines = fsub.readlines() fsub.close() except: qtlib.WarningMsgBox( _('Failed to add subrepository'), _('Cannot open the .hgsub file in:<br><br>%s') \ % root, parent=self) return # Make sure that the selected subrepo (or one of its # subrepos!) is not already on the .hgsub file linesep = '' for line in lines: line = hglib.tounicode(line) spath = line.split("=")[0].strip() if not spath: continue if not linesep: linesep = hglib.getLineSeparator(line) spath = util.pconvert(spath) if line.startswith(srelroot): qtlib.WarningMsgBox( _('Failed to add repository'), _('The .hgsub file already contains the ' 'line:<br><br>%s') % line, parent=self) return if not linesep: linesep = os.linesep # Append the new subrepo to the end of the .hgsub file lines.append( hglib.fromunicode('%s = %s' % (srelroot, srelroot))) lines = [line.strip(linesep) for line in lines] # and update the .hgsub file try: fsub = repo.wopener('.hgsub', 'w') fsub.write(linesep.join(lines) + linesep) fsub.close() if not hasHgsub: commands.add(ui.ui(), repo, repo.wjoin('.hgsub')) qtlib.InfoMsgBox( _('Subrepo added to .hgsub file'), _('The selected subrepo:<br><br><i>%s</i><br><br>' 'has been added to the .hgsub file of the repository:<br><br><i>%s</i><br><br>' 'Remember that in order to finish adding the ' 'subrepo <i>you must still <u>commit</u></i> the ' 'changes to the .hgsub file in order to confirm ' 'the addition of the subrepo.') \ % (srelroot, root), parent=self) except: qtlib.WarningMsgBox( _('Failed to add repository'), _('Cannot update the .hgsub file in:<br><br>%s') \ % root, parent=self) return