8
8
#include "submodule.h"
9
9
#include "submodule-config.h"
10
10
#include "string-list.h"
11
+ #include "run-command.h"
11
12
12
13
struct module_list {
13
14
const struct cache_entry * * entries ;
@@ -123,6 +124,136 @@ static int module_name(int argc, const char **argv, const char *prefix)
123
124
124
125
return 0 ;
125
126
}
127
+ static int clone_submodule (const char * path , const char * gitdir , const char * url ,
128
+ const char * depth , const char * reference , int quiet )
129
+ {
130
+ struct child_process cp ;
131
+ child_process_init (& cp );
132
+
133
+ argv_array_push (& cp .args , "clone" );
134
+ argv_array_push (& cp .args , "--no-checkout" );
135
+ if (quiet )
136
+ argv_array_push (& cp .args , "--quiet" );
137
+ if (depth && * depth )
138
+ argv_array_pushl (& cp .args , "--depth" , depth , NULL );
139
+ if (reference && * reference )
140
+ argv_array_pushl (& cp .args , "--reference" , reference , NULL );
141
+ if (gitdir && * gitdir )
142
+ argv_array_pushl (& cp .args , "--separate-git-dir" , gitdir , NULL );
143
+
144
+ argv_array_push (& cp .args , url );
145
+ argv_array_push (& cp .args , path );
146
+
147
+ cp .git_cmd = 1 ;
148
+ cp .env = local_repo_env ;
149
+ cp .no_stdin = 1 ;
150
+
151
+ return run_command (& cp );
152
+ }
153
+
154
+ static int module_clone (int argc , const char * * argv , const char * prefix )
155
+ {
156
+ const char * path = NULL , * name = NULL , * url = NULL ;
157
+ const char * reference = NULL , * depth = NULL ;
158
+ int quiet = 0 ;
159
+ FILE * submodule_dot_git ;
160
+ char * sm_gitdir , * cwd , * p ;
161
+ struct strbuf rel_path = STRBUF_INIT ;
162
+ struct strbuf sb = STRBUF_INIT ;
163
+
164
+ struct option module_clone_options [] = {
165
+ OPT_STRING (0 , "prefix" , & prefix ,
166
+ N_ ("path" ),
167
+ N_ ("alternative anchor for relative paths" )),
168
+ OPT_STRING (0 , "path" , & path ,
169
+ N_ ("path" ),
170
+ N_ ("where the new submodule will be cloned to" )),
171
+ OPT_STRING (0 , "name" , & name ,
172
+ N_ ("string" ),
173
+ N_ ("name of the new submodule" )),
174
+ OPT_STRING (0 , "url" , & url ,
175
+ N_ ("string" ),
176
+ N_ ("url where to clone the submodule from" )),
177
+ OPT_STRING (0 , "reference" , & reference ,
178
+ N_ ("string" ),
179
+ N_ ("reference repository" )),
180
+ OPT_STRING (0 , "depth" , & depth ,
181
+ N_ ("string" ),
182
+ N_ ("depth for shallow clones" )),
183
+ OPT__QUIET (& quiet , "Suppress output for cloning a submodule" ),
184
+ OPT_END ()
185
+ };
186
+
187
+ const char * const git_submodule_helper_usage [] = {
188
+ N_ ("git submodule--helper clone [--prefix=<path>] [--quiet] "
189
+ "[--reference <repository>] [--name <name>] [--url <url>]"
190
+ "[--depth <depth>] [--] [<path>...]" ),
191
+ NULL
192
+ };
193
+
194
+ argc = parse_options (argc , argv , prefix , module_clone_options ,
195
+ git_submodule_helper_usage , 0 );
196
+
197
+ strbuf_addf (& sb , "%s/modules/%s" , get_git_dir (), name );
198
+ sm_gitdir = strbuf_detach (& sb , NULL );
199
+
200
+ if (!file_exists (sm_gitdir )) {
201
+ if (safe_create_leading_directories_const (sm_gitdir ) < 0 )
202
+ die (_ ("could not create directory '%s'" ), sm_gitdir );
203
+ if (clone_submodule (path , sm_gitdir , url , depth , reference , quiet ))
204
+ die (_ ("clone of '%s' into submodule path '%s' failed" ),
205
+ url , path );
206
+ } else {
207
+ if (safe_create_leading_directories_const (path ) < 0 )
208
+ die (_ ("could not create directory '%s'" ), path );
209
+ strbuf_addf (& sb , "%s/index" , sm_gitdir );
210
+ unlink_or_warn (sb .buf );
211
+ strbuf_reset (& sb );
212
+ }
213
+
214
+ /* Write a .git file in the submodule to redirect to the superproject. */
215
+ if (safe_create_leading_directories_const (path ) < 0 )
216
+ die (_ ("could not create directory '%s'" ), path );
217
+
218
+ if (path && * path )
219
+ strbuf_addf (& sb , "%s/.git" , path );
220
+ else
221
+ strbuf_addstr (& sb , ".git" );
222
+
223
+ if (safe_create_leading_directories_const (sb .buf ) < 0 )
224
+ die (_ ("could not create leading directories of '%s'" ), sb .buf );
225
+ submodule_dot_git = fopen (sb .buf , "w" );
226
+ if (!submodule_dot_git )
227
+ die_errno (_ ("cannot open file '%s'" ), sb .buf );
228
+
229
+ fprintf (submodule_dot_git , "gitdir: %s\n" ,
230
+ relative_path (sm_gitdir , path , & rel_path ));
231
+ if (fclose (submodule_dot_git ))
232
+ die (_ ("could not close file %s" ), sb .buf );
233
+ strbuf_reset (& sb );
234
+ strbuf_reset (& rel_path );
235
+
236
+ cwd = xgetcwd ();
237
+ /* Redirect the worktree of the submodule in the superproject's config */
238
+ if (!is_absolute_path (sm_gitdir )) {
239
+ strbuf_addf (& sb , "%s/%s" , cwd , sm_gitdir );
240
+ free (sm_gitdir );
241
+ sm_gitdir = strbuf_detach (& sb , NULL );
242
+ }
243
+
244
+ strbuf_addf (& sb , "%s/%s" , cwd , path );
245
+ p = git_pathdup_submodule (path , "config" );
246
+ if (!p )
247
+ die (_ ("could not get submodule directory for '%s'" ), path );
248
+ git_config_set_in_file (p , "core.worktree" ,
249
+ relative_path (sb .buf , sm_gitdir , & rel_path ));
250
+ strbuf_release (& sb );
251
+ strbuf_release (& rel_path );
252
+ free (sm_gitdir );
253
+ free (cwd );
254
+ free (p );
255
+ return 0 ;
256
+ }
126
257
127
258
struct cmd_struct {
128
259
const char * cmd ;
@@ -132,6 +263,7 @@ struct cmd_struct {
132
263
static struct cmd_struct commands [] = {
133
264
{"list" , module_list },
134
265
{"name" , module_name },
266
+ {"clone" , module_clone },
135
267
};
136
268
137
269
int cmd_submodule__helper (int argc , const char * * argv , const char * prefix )
0 commit comments