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