1 from __future__
import division
, absolute_import
, 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, settings
=None, parent
=None):
23 """Clone a repository and spawn a new git-cola instance"""
24 parent
= qtutils
.active_window()
25 progress
= standard
.ProgressDialog('', '', parent
)
26 return clone_repo(context
, parent
, show
, settings
,
27 progress
, task_finished
, spawn
)
30 def clone_repo(context
, parent
, show
, settings
, progress
, finish
, spawn
):
31 """Clone a repository asynchronously with progress animation"""
32 fn
= partial(start_clone_task
, context
, parent
, progress
, finish
, spawn
)
33 prompt
= prompt_for_clone(context
, show
=show
, settings
=settings
)
34 prompt
.result
.connect(fn
)
38 def prompt_for_clone(context
, show
=True, settings
=None):
39 """Presents a GUI for cloning a repository"""
40 view
= Clone(context
, settings
=settings
, parent
=qtutils
.active_window())
46 def task_finished(task
):
47 """Report errors from the clone task if they exist"""
54 title
= N_('Error: could not clone "%s"') % cmd
.url
55 Interaction
.command(title
, 'git clone', status
, out
, err
)
58 def start_clone_task(context
, parent
, progress
, finish
, spawn
, url
, destdir
,
60 # Use a thread to update in the background
61 runtask
= context
.runtask
62 progress
.set_details(N_('Clone Repository'),
63 N_('Cloning repository at %s') % url
)
64 task
= CloneTask(context
, url
, destdir
, submodules
, shallow
, spawn
, parent
)
65 runtask
.start(task
, finish
=finish
, progress
=progress
)
68 class CloneTask(qtutils
.Task
):
69 """Clones a Git repository"""
71 def __init__(self
, context
, url
, destdir
, submodules
,
72 shallow
, spawn
, parent
):
73 qtutils
.Task
.__init
__(self
, parent
)
74 self
.context
= context
76 self
.destdir
= destdir
77 self
.submodules
= submodules
78 self
.shallow
= shallow
83 """Runs the model action and captures the result"""
85 cmds
.Clone
, self
.context
, self
.url
, self
.destdir
,
86 self
.submodules
, self
.shallow
, spawn
=self
.spawn
)
90 class Clone(standard
.Dialog
):
92 # Signal binding for returning the input data
93 result
= QtCore
.Signal(object, object, bool, bool)
95 def __init__(self
, context
, settings
=None, parent
=None):
96 standard
.Dialog
.__init
__(self
, parent
=parent
)
97 self
.context
= context
98 self
.model
= context
.model
100 self
.setWindowTitle(N_('Clone Repository'))
101 if parent
is not None:
102 self
.setWindowModality(Qt
.WindowModal
)
104 # Repository location
105 self
.url_label
= QtWidgets
.QLabel(N_('URL'))
106 hint
= 'git://git.example.com/repo.git'
107 self
.url
= text
.HintedLineEdit(context
, hint
, parent
=self
)
108 self
.url
.setToolTip(N_('Path or URL to clone (Env. $VARS okay)'))
110 # Initialize submodules
111 self
.submodules
= qtutils
.checkbox(
112 text
=N_('Inititalize submodules'), checked
=False)
114 # Reduce commit history
115 self
.shallow
= qtutils
.checkbox(
116 text
=N_('Reduce commit history to minimum'), checked
=False)
119 self
.ok_button
= qtutils
.create_button(
120 text
=N_('Clone'), icon
=icons
.ok(), default
=True)
121 self
.close_button
= qtutils
.close_button()
123 # Form layout for inputs
124 self
.input_layout
= qtutils
.form(
125 defs
.no_margin
, defs
.button_spacing
,
126 (self
.url_label
, self
.url
))
128 self
.button_layout
= qtutils
.hbox(
129 defs
.margin
, defs
.spacing
,
130 self
.submodules
, defs
.button_spacing
,
131 self
.shallow
, qtutils
.STRETCH
,
132 self
.ok_button
, self
.close_button
)
134 self
.main_layout
= qtutils
.vbox(defs
.margin
, defs
.spacing
,
135 self
.input_layout
, self
.button_layout
)
136 self
.setLayout(self
.main_layout
)
138 qtutils
.connect_button(self
.close_button
, self
.close
)
139 qtutils
.connect_button(self
.ok_button
, self
.prepare_to_clone
)
140 self
.url
.textChanged
.connect(lambda x
: self
.update_actions())
142 self
.init_state(settings
, self
.resize
, 720, 200)
143 self
.update_actions()
145 def update_actions(self
):
146 url
= get(self
.url
).strip()
148 self
.ok_button
.setEnabled(enabled
)
150 def prepare_to_clone(self
):
151 """Grabs and validates the input data"""
153 submodules
= get(self
.submodules
)
154 shallow
= get(self
.shallow
)
157 url
= utils
.expandpath(url
)
160 # Pick a suitable basename by parsing the URL
161 newurl
= url
.replace('\\', '/').rstrip('/')
163 default
= newurl
.rsplit('/', 1)[-1]
166 if default
== '.git':
167 # The end of the URL is /.git, so assume it's a file path
168 default
= os
.path
.basename(os
.path
.dirname(newurl
))
169 if default
.endswith('.git'):
170 # The URL points to a bare repo
171 default
= default
[:-4]
173 # The URL is the current repo
174 default
= os
.path
.basename(core
.getcwd())
176 Interaction
.information(
178 N_('Could not parse Git URL: "%s"') % url
)
179 Interaction
.log(N_('Could not parse Git URL: "%s"') % url
)
182 # Prompt the user for a directory to use as the parent directory
183 msg
= N_('Select a parent directory for the new clone')
184 dirname
= qtutils
.opendir_dialog(msg
, self
.model
.getcwd())
188 destdir
= os
.path
.join(dirname
, default
)
190 if core
.exists(destdir
):
191 # An existing path can be specified
193 N_('"%s" already exists, cola will create a new directory')
195 Interaction
.information(N_('Directory Exists'), msg
)
197 # Make sure the new destdir doesn't exist
198 while core
.exists(destdir
):
199 destdir
= olddestdir
+ str(count
)
202 # Return the input data and close the dialog
203 self
.result
.emit(url
, destdir
, submodules
, shallow
)