dag: call wait() when the subprocess finishes
[git-cola.git] / cola / guicmds.py
blob3d6fca202c367ba6575b4775ad8d0250feb58732
1 import os
2 import re
4 from PyQt4 import QtGui
6 import cola
7 from cola import cmds
8 from cola import core
9 from cola import difftool
10 from cola import gitcmds
11 from cola import qt
12 from cola import qtutils
13 from cola import utils
14 from cola.git import git
15 from cola.i18n import N_
16 from cola.interaction import Interaction
17 from cola.widgets.browse import BrowseDialog
18 from cola.widgets.grep import run_grep
19 from cola.widgets.selectcommits import select_commits
23 def delete_branch():
24 """Launch the 'Delete Branch' dialog."""
25 branch = choose_branch(N_('Delete Branch'), N_('Delete'))
26 if not branch:
27 return
28 cmds.do(cmds.DeleteBranch, branch)
31 def delete_remote_branch():
32 """Launch the 'Delete Remote Branch' dialog."""
33 branch = choose_remote_branch(N_('Delete Remote Branch'), N_('Delete'))
34 if not branch:
35 return
36 rgx = re.compile(r'^(?P<remote>[^/]+)/(?P<branch>.+)$')
37 match = rgx.match(branch)
38 if match:
39 remote = match.group('remote')
40 branch = match.group('branch')
41 cmds.do(cmds.DeleteRemoteBranch, remote, branch)
44 def browse_current():
45 """Launch the 'Browse Current Branch' dialog."""
46 branch = gitcmds.current_branch()
47 BrowseDialog.browse(branch)
50 def browse_other():
51 """Prompt for a branch and inspect content at that point in time."""
52 # Prompt for a branch to browse
53 branch = choose_ref(N_('Browse Commits...'), N_('Browse'))
54 if not branch:
55 return
56 BrowseDialog.browse(branch)
59 def checkout_branch():
60 """Launch the 'Checkout Branch' dialog."""
61 branch = choose_branch(N_('Checkout Branch'), N_('Checkout'))
62 if not branch:
63 return
64 cmds.do(cmds.CheckoutBranch, branch)
67 def cherry_pick():
68 """Launch the 'Cherry-Pick' dialog."""
69 revs, summaries = gitcmds.log_helper(all=True)
70 commits = select_commits(N_('Cherry-Pick Commit'),
71 revs, summaries, multiselect=False)
72 if not commits:
73 return
74 cmds.do(cmds.CherryPick, commits)
77 def new_repo():
78 """Prompt for a new directory and create a new Git repository
80 :returns str: repository path or None if no repository was created.
82 """
83 dlg = QtGui.QFileDialog()
84 dlg.setFileMode(QtGui.QFileDialog.Directory)
85 dlg.setOption(QtGui.QFileDialog.ShowDirsOnly)
86 dlg.show()
87 dlg.raise_()
88 if dlg.exec_() != QtGui.QFileDialog.Accepted:
89 return None
90 paths = dlg.selectedFiles()
91 if not paths:
92 return None
93 path = unicode(paths[0])
94 if not path:
95 return None
96 # Avoid needlessly calling `git init`.
97 if git.is_git_dir(path):
98 # We could prompt here and confirm that they really didn't
99 # mean to open an existing repository, but I think
100 # treating it like an "Open" is a sensible DWIM answer.
101 return path
103 status, out, err = utils.run_command(['git', 'init', path])
104 if status == 0:
105 return path
106 else:
107 title = N_('Error Creating Repository')
108 msg = (N_('"%(command)s" returned exit status %(status)d') %
109 dict(command='git init %s' % path, status=status))
110 details = N_('Output:\n%s') % out
111 if err:
112 details += '\n\n'
113 details += N_('Errors: %s') % err
114 qtutils.critical(title, msg, details)
115 return None
118 def open_new_repo():
119 dirname = new_repo()
120 if not dirname:
121 return
122 cmds.do(cmds.OpenRepo, dirname)
125 def clone_repo(spawn=True):
127 Present GUI controls for cloning a repository
129 A new cola session is invoked when 'spawn' is True.
132 url, ok = qtutils.prompt(N_('Path or URL to clone (Env. $VARS okay)'))
133 url = os.path.expandvars(url)
134 if not ok or not url:
135 return None
136 try:
137 # Pick a suitable basename by parsing the URL
138 newurl = url.replace('\\', '/').rstrip('/')
139 default = newurl.rsplit('/', 1)[-1]
140 if default == '.git':
141 # The end of the URL is /.git, so assume it's a file path
142 default = os.path.basename(os.path.dirname(newurl))
143 if default.endswith('.git'):
144 # The URL points to a bare repo
145 default = default[:-4]
146 if url == '.':
147 # The URL is the current repo
148 default = os.path.basename(core.getcwd())
149 if not default:
150 raise
151 except:
152 Interaction.information(
153 N_('Error Cloning'),
154 N_('Could not parse Git URL: "%s"') % url)
155 Interaction.log(N_('Could not parse Git URL: "%s"') % url)
156 return None
158 # Prompt the user for a directory to use as the parent directory
159 msg = N_('Select a parent directory for the new clone')
160 dirname = qtutils.opendir_dialog(msg, cola.model().getcwd())
161 if not dirname:
162 return None
163 count = 1
164 destdir = os.path.join(dirname, default)
165 olddestdir = destdir
166 if core.exists(destdir):
167 # An existing path can be specified
168 msg = (N_('"%s" already exists, cola will create a new directory') %
169 destdir)
170 Interaction.information('Directory Exists', msg)
172 # Make sure the new destdir doesn't exist
173 while core.exists(destdir):
174 destdir = olddestdir + str(count)
175 count += 1
176 if cmds.do(cmds.Clone, url, destdir, spawn=spawn):
177 return destdir
178 return None
181 def export_patches():
182 """Run 'git format-patch' on a list of commits."""
183 revs, summaries = gitcmds.log_helper()
184 to_export = select_commits(N_('Export Patches'), revs, summaries)
185 if not to_export:
186 return
187 to_export.reverse()
188 revs.reverse()
189 cmds.do(cmds.FormatPatch, to_export, revs)
192 def diff_expression():
193 """Diff using an arbitrary expression."""
194 tracked = gitcmds.tracked_branch()
195 current = gitcmds.current_branch()
196 if tracked and current:
197 ref = tracked + '..' + current
198 else:
199 ref = 'origin/master..'
200 difftool.diff_expression(qtutils.active_window(), ref)
203 def grep():
204 """Prompt and use 'git grep' to find the content."""
205 widget = run_grep(parent=qtutils.active_window())
206 widget.show()
207 widget.raise_()
208 return widget
211 def open_repo():
212 """Spawn a new cola session."""
213 dirname = qtutils.opendir_dialog(N_('Open Git Repository...'),
214 cola.model().getcwd())
215 if not dirname:
216 return
217 cmds.do(cmds.OpenRepo, dirname)
220 def load_commitmsg():
221 """Load a commit message from a file."""
222 filename = qtutils.open_dialog(N_('Load Commit Message'),
223 cola.model().getcwd())
224 if filename:
225 cmds.do(cmds.LoadCommitMessageFromFile, filename)
228 def choose_from_dialog(get, title, button_text, default):
229 parent = qtutils.active_window()
230 return get(title, button_text, parent, default=default)
233 def choose_ref(title, button_text, default=None):
234 return choose_from_dialog(qt.GitRefDialog.get,
235 title, button_text, default)
238 def choose_branch(title, button_text, default=None):
239 return choose_from_dialog(qt.GitBranchDialog.get,
240 title, button_text, default)
243 def choose_remote_branch(title, button_text, default=None):
244 return choose_from_dialog(qt.GitRemoteBranchDialog.get,
245 title, button_text, default)
248 def review_branch():
249 """Diff against an arbitrary revision, branch, tag, etc."""
250 branch = choose_ref(N_('Select Branch to Review'), N_('Review'))
251 if not branch:
252 return
253 merge_base = gitcmds.merge_base_parent(branch)
254 difftool.diff_commits(qtutils.active_window(), merge_base, branch)