pylint: rename variables for readability
[git-cola.git] / cola / widgets / clone.py
blob460c70b27f3f98a2b86ca080e299d3a43d528f97
1 from __future__ import absolute_import, division, print_function, unicode_literals
2 import os
3 from functools import partial
5 from qtpy import QtCore
6 from qtpy import QtWidgets
7 from qtpy.QtCore import Qt
9 from .. import cmds
10 from .. import core
11 from .. import icons
12 from .. import utils
13 from .. import qtutils
14 from ..i18n import N_
15 from ..interaction import Interaction
16 from ..qtutils import get
17 from . import defs
18 from . import standard
19 from . import text
22 def clone(context, spawn=True, show=True):
23 """Clone a repository and spawn a new git-cola instance"""
24 parent = qtutils.active_window()
25 progress = standard.progress('', '', parent)
26 return clone_repo(context, show, progress, task_finished, spawn)
29 def clone_repo(context, show, progress, finish, spawn):
30 """Clone a repository asynchronously with progress animation"""
31 func = partial(start_clone_task, context, progress, finish, spawn)
32 prompt = prompt_for_clone(context, show=show)
33 prompt.result.connect(func)
34 return prompt
37 def prompt_for_clone(context, show=True):
38 """Presents a GUI for cloning a repository"""
39 view = Clone(context, parent=qtutils.active_window())
40 if show:
41 view.show()
42 return view
45 def task_finished(task):
46 """Report errors from the clone task if they exist"""
47 cmd = task.cmd
48 if cmd is None:
49 return
50 status = cmd.status
51 out = cmd.out
52 err = cmd.err
53 title = N_('Error: could not clone "%s"') % cmd.url
54 Interaction.command(title, 'git clone', status, out, err)
57 def start_clone_task(
58 context, progress, finish, spawn, url, destdir, submodules, shallow
60 # Use a thread to update in the background
61 runtask = context.runtask
62 progress.set_details(N_('Clone Repository'), N_('Cloning repository at %s') % url)
63 task = CloneTask(context, url, destdir, submodules, shallow, spawn)
64 runtask.start(task, finish=finish, progress=progress)
67 class CloneTask(qtutils.Task):
68 """Clones a Git repository"""
70 def __init__(self, context, url, destdir, submodules, shallow, spawn):
71 qtutils.Task.__init__(self)
72 self.context = context
73 self.url = url
74 self.destdir = destdir
75 self.submodules = submodules
76 self.shallow = shallow
77 self.spawn = spawn
78 self.cmd = None
80 def task(self):
81 """Runs the model action and captures the result"""
82 self.cmd = cmds.do(
83 cmds.Clone,
84 self.context,
85 self.url,
86 self.destdir,
87 self.submodules,
88 self.shallow,
89 spawn=self.spawn,
91 return self.cmd
94 class Clone(standard.Dialog):
96 # Signal binding for returning the input data
97 result = QtCore.Signal(object, object, bool, bool)
99 def __init__(self, context, parent=None):
100 standard.Dialog.__init__(self, parent=parent)
101 self.context = context
102 self.model = context.model
104 self.setWindowTitle(N_('Clone Repository'))
105 if parent is not None:
106 self.setWindowModality(Qt.WindowModal)
108 # Repository location
109 self.url_label = QtWidgets.QLabel(N_('URL'))
110 hint = 'git://git.example.com/repo.git'
111 self.url = text.HintedLineEdit(context, hint, parent=self)
112 self.url.setToolTip(N_('Path or URL to clone (Env. $VARS okay)'))
114 # Initialize submodules
115 self.submodules = qtutils.checkbox(
116 text=N_('Inititalize submodules'), checked=False
119 # Reduce commit history
120 self.shallow = qtutils.checkbox(
121 text=N_('Reduce commit history to minimum'), checked=False
124 # Buttons
125 self.ok_button = qtutils.create_button(
126 text=N_('Clone'), icon=icons.ok(), default=True
128 self.close_button = qtutils.close_button()
130 # Form layout for inputs
131 self.input_layout = qtutils.form(
132 defs.no_margin, defs.button_spacing, (self.url_label, self.url)
135 self.button_layout = qtutils.hbox(
136 defs.margin,
137 defs.spacing,
138 self.submodules,
139 defs.button_spacing,
140 self.shallow,
141 qtutils.STRETCH,
142 self.close_button,
143 self.ok_button,
146 self.main_layout = qtutils.vbox(
147 defs.margin, defs.spacing, self.input_layout, self.button_layout
149 self.setLayout(self.main_layout)
151 qtutils.connect_button(self.close_button, self.close)
152 qtutils.connect_button(self.ok_button, self.prepare_to_clone)
153 # pylint: disable=no-member
154 self.url.textChanged.connect(lambda x: self.update_actions())
156 self.init_state(context.settings, self.resize, 720, 200)
157 self.update_actions()
159 def update_actions(self):
160 url = get(self.url).strip()
161 enabled = bool(url)
162 self.ok_button.setEnabled(enabled)
164 def prepare_to_clone(self):
165 """Grabs and validates the input data"""
167 submodules = get(self.submodules)
168 shallow = get(self.shallow)
170 url = get(self.url)
171 url = utils.expandpath(url)
172 if not url:
173 return
174 # Pick a suitable basename by parsing the URL
175 newurl = url.replace('\\', '/').rstrip('/')
176 try:
177 default = newurl.rsplit('/', 1)[-1]
178 except IndexError:
179 default = ''
180 if default == '.git':
181 # The end of the URL is /.git, so assume it's a file path
182 default = os.path.basename(os.path.dirname(newurl))
183 if default.endswith('.git'):
184 # The URL points to a bare repo
185 default = default[:-4]
186 if url == '.':
187 # The URL is the current repo
188 default = os.path.basename(core.getcwd())
189 if not default:
190 Interaction.information(
191 N_('Error Cloning'), N_('Could not parse Git URL: "%s"') % url
193 Interaction.log(N_('Could not parse Git URL: "%s"') % url)
194 return
196 # Prompt the user for a directory to use as the parent directory
197 msg = N_('Select a parent directory for the new clone')
198 dirname = qtutils.opendir_dialog(msg, self.model.getcwd())
199 if not dirname:
200 return
201 count = 1
202 destdir = os.path.join(dirname, default)
203 olddestdir = destdir
204 if core.exists(destdir):
205 # An existing path can be specified
206 msg = N_('"%s" already exists, cola will create a new directory') % destdir
207 Interaction.information(N_('Directory Exists'), msg)
209 # Make sure the new destdir doesn't exist
210 while core.exists(destdir):
211 destdir = olddestdir + str(count)
212 count += 1
214 # Return the input data and close the dialog
215 self.result.emit(url, destdir, submodules, shallow)
216 self.close()