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