1 from __future__
import absolute_import
, division
, print_function
, unicode_literals
3 from functools
import partial
5 from qtpy
import QtCore
6 from qtpy
import QtWidgets
7 from qtpy
.QtCore
import Qt
13 from .. import qtutils
15 from ..interaction
import Interaction
16 from ..qtutils
import get
18 from . import standard
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
)
37 def prompt_for_clone(context
, show
=True):
38 """Presents a GUI for cloning a repository"""
39 view
= Clone(context
, parent
=qtutils
.active_window())
45 def task_finished(task
):
46 """Report errors from the clone task if they exist"""
53 title
= N_('Error: could not clone "%s"') % cmd
.url
54 Interaction
.command(title
, 'git clone', status
, out
, err
)
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
74 self
.destdir
= destdir
75 self
.submodules
= submodules
76 self
.shallow
= shallow
81 """Runs the model action and captures the result"""
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
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(
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()
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
)
171 url
= utils
.expandpath(url
)
174 # Pick a suitable basename by parsing the URL
175 newurl
= url
.replace('\\', '/').rstrip('/')
177 default
= newurl
.rsplit('/', 1)[-1]
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]
187 # The URL is the current repo
188 default
= os
.path
.basename(core
.getcwd())
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
)
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())
202 destdir
= os
.path
.join(dirname
, default
)
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
)
214 # Return the input data and close the dialog
215 self
.result
.emit(url
, destdir
, submodules
, shallow
)