Fossil SCM

Enhance the clone command so that if it includes either the "--workdir DIR" option, or if omits the local repository filename argument, and if the "--no-open" option is omitted, then the repository is opened after it is cloned. Hence the command "fossil clone https://whatever.com/x/y/repo" works more like Git in that it first clones into "repo.fossil" then opens the new repository in the "repo" subdirectory.

drh 2020-11-01 20:06 trunk
Commit a8d7878789da6e33e3cba8f8e0be5e3741a432543031214c8dad14ed0db7c32d
1 file changed +63 -23
+63 -23
--- src/clone.c
+++ src/clone.c
@@ -80,15 +80,17 @@
8080
8181
8282
/*
8383
** COMMAND: clone
8484
**
85
-** Usage: %fossil clone ?OPTIONS? URI FILENAME
85
+** Usage: %fossil clone ?OPTIONS? URI ?FILENAME?
8686
**
8787
** Make a clone of a repository specified by URI in the local
88
-** file named FILENAME. URI may be one of the following forms:
89
-** ([...] denotes optional elements):
88
+** file named FILENAME. If FILENAME is omitted, then an appropriate
89
+** filename is deduced from last element of the path in the URL.
90
+**
91
+** URI may be one of the following forms ([...] denotes optional elements):
9092
**
9193
** * HTTP/HTTPS protocol:
9294
**
9395
** http[s]://[userid[:password]@]host[:port][/path]
9496
**
@@ -98,36 +100,43 @@
98100
**
99101
** * Filesystem:
100102
**
101103
** [file://]path/to/repo.fossil
102104
**
103
-** Note that in Fossil (in contrast to some other DVCSes) a repository
104
-** is distinct from a checkout. This command create a clone of a repository.
105
-** Use the separate [[open]] command to open a checkout from that repository.
106
-**
107105
** For ssh and filesystem, path must have an extra leading
108106
** '/' to use an absolute path.
109107
**
110108
** Use %HH escapes for special characters in the userid and
111109
** password. For example "%40" in place of "@", "%2f" in place
112110
** of "/", and "%3a" in place of ":".
111
+**
112
+** Note that in Fossil (in contrast to some other DVCSes) a repository
113
+** is distinct from a checkout. Cloning a repository is not the same thing
114
+** as opening a repository. This command always clones the repository. This
115
+** command might also open the repository, but only if the --no-open option
116
+** is omitted and either the --workdir option is included or the FILENAME
117
+** argument is omitted. Use the separate [[open]] command to open a
118
+** repository that was previously cloned and already exists on the
119
+** local machine.
113120
**
114121
** By default, the current login name is used to create the default
115
-** admin user. This can be overridden using the -A|--admin-user
116
-** parameter.
122
+** admin user for the new clone. This can be overridden using
123
+** the -A|--admin-user parameter.
117124
**
118125
** Options:
119126
** --admin-user|-A USERNAME Make USERNAME the administrator
120127
** --httpauth|-B USER:PASS Add HTTP Basic Authorization to requests
121128
** --nocompress Omit extra delta compression
129
+** --no-open Clone only. Do not open a check-out.
122130
** --once Don't remember the URI.
123131
** --private Also clone private branches
124132
** --save-http-password Remember the HTTP password without asking
125133
** --ssh-command|-c SSH Use SSH as the "ssh" command
126134
** --ssl-identity FILENAME Use the SSL identity if requested by the server
127135
** -u|--unversioned Also sync unversioned content
128136
** -v|--verbose Show more statistics in output
137
+** --workdir DIR Also open a checkout in DIR
129138
**
130139
** See also: [[init]], [[open]]
131140
*/
132141
void clone_cmd(void){
133142
char *zPassword;
@@ -135,10 +144,14 @@
135144
const char *zHttpAuth; /* HTTP Authorization user:pass information */
136145
int nErr = 0;
137146
int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
138147
int syncFlags = SYNC_CLONE;
139148
int noCompress = find_option("nocompress",0,0)!=0;
149
+ int noOpen = find_option("no-open",0,0)!=0;
150
+ const char *zRepo = 0; /* Name of the new local repository file */
151
+ const char *zWorkDir = 0; /* Open in this director, if not zero */
152
+
140153
141154
/* Also clone private branches */
142155
if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
143156
if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
144157
if( find_option("save-http-password",0,0)!=0 ){
@@ -147,49 +160,62 @@
147160
}
148161
if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE;
149162
if( find_option("unversioned","u",0)!=0 ) syncFlags |= SYNC_UNVERSIONED;
150163
zHttpAuth = find_option("httpauth","B",1);
151164
zDefaultUser = find_option("admin-user","A",1);
165
+ zWorkDir = find_option("workdir", 0, 1);
152166
clone_ssh_find_options();
153167
url_proxy_options();
154168
155169
/* We should be done with options.. */
156170
verify_all_options();
157171
158
- if( g.argc < 4 ){
159
- usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
172
+ if( g.argc < 3 ){
173
+ usage("?OPTIONS? FILE-OR-URL ?NEW-REPOSITORY?");
160174
}
161175
db_open_config(0, 0);
162
- if( -1 != file_size(g.argv[3], ExtFILE) ){
163
- fossil_fatal("file already exists: %s", g.argv[3]);
176
+ zRepo = g.argc==4 ? g.argv[3] : 0;
177
+ if( zRepo!=0 && -1 != file_size(zRepo, ExtFILE) ){
178
+ fossil_fatal("file already exists: %s", zRepo);
164179
}
165
-
166180
url_parse(g.argv[2], urlFlags);
181
+ if( zRepo==0 ){
182
+ int i;
183
+ const char *z = file_tail(g.url.isFile ? g.url.name : g.url.path);
184
+ for(i=0; z[i] && z[i]!='.'; i++){}
185
+ if( zWorkDir==0 ){
186
+ zWorkDir = mprintf("./%.*s", i, z);
187
+ }
188
+ zRepo = mprintf("./%.*s.fossil", i, z);
189
+ if( -1 != file_size(zRepo, ExtFILE) ){
190
+ fossil_fatal("file already exists: %s", zRepo);
191
+ }
192
+ }
167193
if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
168194
if( g.url.isFile ){
169
- file_copy(g.url.name, g.argv[3]);
195
+ file_copy(g.url.name, zRepo);
170196
db_close(1);
171
- db_open_repository(g.argv[3]);
197
+ db_open_repository(zRepo);
172198
db_open_config(1,0);
173
- db_record_repository_filename(g.argv[3]);
199
+ db_record_repository_filename(zRepo);
174200
url_remember();
175201
if( !(syncFlags & SYNC_PRIVATE) ) delete_private_content();
176202
shun_artifacts();
177203
db_create_default_users(1, zDefaultUser);
178204
if( zDefaultUser ){
179205
g.zLogin = zDefaultUser;
180206
}else{
181207
g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'");
182208
}
183
- fossil_print("Repository cloned into %s\n", g.argv[3]);
209
+ fossil_print("Repository cloned into %s\n", zRepo);
184210
}else{
185211
db_close_config();
186
- db_create_repository(g.argv[3]);
187
- db_open_repository(g.argv[3]);
212
+ db_create_repository(zRepo);
213
+ db_open_repository(zRepo);
188214
db_open_config(0,0);
189215
db_begin_transaction();
190
- db_record_repository_filename(g.argv[3]);
216
+ db_record_repository_filename(zRepo);
191217
db_initial_setup(0, 0, zDefaultUser);
192218
user_select();
193219
db_set("content-schema", CONTENT_SCHEMA, 0);
194220
db_set("aux-schema", AUX_SCHEMA_MAX, 0);
195221
db_set("rebuilt", get_version(), 0);
@@ -221,14 +247,14 @@
221247
g.xlinkClusterOnly = 0;
222248
verify_cancel();
223249
db_end_transaction(0);
224250
db_close(1);
225251
if( nErr ){
226
- file_delete(g.argv[3]);
252
+ file_delete(zRepo);
227253
fossil_fatal("server returned an error - clone aborted");
228254
}
229
- db_open_repository(g.argv[3]);
255
+ db_open_repository(zRepo);
230256
}
231257
db_begin_transaction();
232258
fossil_print("Rebuilding repository meta-data...\n");
233259
rebuild_db(0, 1, 0);
234260
if( !noCompress ){
@@ -247,10 +273,24 @@
247273
db_protect_pop();
248274
fossil_print("\nproject-id: %s\n", db_get("project-code", 0));
249275
fossil_print("server-id: %s\n", db_get("server-code", 0));
250276
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
251277
fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
278
+ if( zWorkDir!=0 && zWorkDir[0]!=0 && !noOpen ){
279
+ char *azNew[6];
280
+ fossil_print("opening the new %s repository in directory %s...\n",
281
+ zRepo, zWorkDir);
282
+ azNew[0] = g.argv[0];
283
+ azNew[1] = "open";
284
+ azNew[2] = (char*)zRepo;
285
+ azNew[3] = "--workdir";
286
+ azNew[4] = (char*)zWorkDir;
287
+ azNew[5] = 0;
288
+ g.argv = azNew;
289
+ g.argc = 5;
290
+ cmd_open();
291
+ }
252292
}
253293
254294
/*
255295
** If user chooses to use HTTP Authentication over unencrypted HTTP,
256296
** remember decision. Otherwise, if the URL is being changed and no
257297
--- src/clone.c
+++ src/clone.c
@@ -80,15 +80,17 @@
80
81
82 /*
83 ** COMMAND: clone
84 **
85 ** Usage: %fossil clone ?OPTIONS? URI FILENAME
86 **
87 ** Make a clone of a repository specified by URI in the local
88 ** file named FILENAME. URI may be one of the following forms:
89 ** ([...] denotes optional elements):
 
 
90 **
91 ** * HTTP/HTTPS protocol:
92 **
93 ** http[s]://[userid[:password]@]host[:port][/path]
94 **
@@ -98,36 +100,43 @@
98 **
99 ** * Filesystem:
100 **
101 ** [file://]path/to/repo.fossil
102 **
103 ** Note that in Fossil (in contrast to some other DVCSes) a repository
104 ** is distinct from a checkout. This command create a clone of a repository.
105 ** Use the separate [[open]] command to open a checkout from that repository.
106 **
107 ** For ssh and filesystem, path must have an extra leading
108 ** '/' to use an absolute path.
109 **
110 ** Use %HH escapes for special characters in the userid and
111 ** password. For example "%40" in place of "@", "%2f" in place
112 ** of "/", and "%3a" in place of ":".
 
 
 
 
 
 
 
 
 
113 **
114 ** By default, the current login name is used to create the default
115 ** admin user. This can be overridden using the -A|--admin-user
116 ** parameter.
117 **
118 ** Options:
119 ** --admin-user|-A USERNAME Make USERNAME the administrator
120 ** --httpauth|-B USER:PASS Add HTTP Basic Authorization to requests
121 ** --nocompress Omit extra delta compression
 
122 ** --once Don't remember the URI.
123 ** --private Also clone private branches
124 ** --save-http-password Remember the HTTP password without asking
125 ** --ssh-command|-c SSH Use SSH as the "ssh" command
126 ** --ssl-identity FILENAME Use the SSL identity if requested by the server
127 ** -u|--unversioned Also sync unversioned content
128 ** -v|--verbose Show more statistics in output
 
129 **
130 ** See also: [[init]], [[open]]
131 */
132 void clone_cmd(void){
133 char *zPassword;
@@ -135,10 +144,14 @@
135 const char *zHttpAuth; /* HTTP Authorization user:pass information */
136 int nErr = 0;
137 int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
138 int syncFlags = SYNC_CLONE;
139 int noCompress = find_option("nocompress",0,0)!=0;
 
 
 
 
140
141 /* Also clone private branches */
142 if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
143 if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
144 if( find_option("save-http-password",0,0)!=0 ){
@@ -147,49 +160,62 @@
147 }
148 if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE;
149 if( find_option("unversioned","u",0)!=0 ) syncFlags |= SYNC_UNVERSIONED;
150 zHttpAuth = find_option("httpauth","B",1);
151 zDefaultUser = find_option("admin-user","A",1);
 
152 clone_ssh_find_options();
153 url_proxy_options();
154
155 /* We should be done with options.. */
156 verify_all_options();
157
158 if( g.argc < 4 ){
159 usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
160 }
161 db_open_config(0, 0);
162 if( -1 != file_size(g.argv[3], ExtFILE) ){
163 fossil_fatal("file already exists: %s", g.argv[3]);
 
164 }
165
166 url_parse(g.argv[2], urlFlags);
 
 
 
 
 
 
 
 
 
 
 
 
167 if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
168 if( g.url.isFile ){
169 file_copy(g.url.name, g.argv[3]);
170 db_close(1);
171 db_open_repository(g.argv[3]);
172 db_open_config(1,0);
173 db_record_repository_filename(g.argv[3]);
174 url_remember();
175 if( !(syncFlags & SYNC_PRIVATE) ) delete_private_content();
176 shun_artifacts();
177 db_create_default_users(1, zDefaultUser);
178 if( zDefaultUser ){
179 g.zLogin = zDefaultUser;
180 }else{
181 g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'");
182 }
183 fossil_print("Repository cloned into %s\n", g.argv[3]);
184 }else{
185 db_close_config();
186 db_create_repository(g.argv[3]);
187 db_open_repository(g.argv[3]);
188 db_open_config(0,0);
189 db_begin_transaction();
190 db_record_repository_filename(g.argv[3]);
191 db_initial_setup(0, 0, zDefaultUser);
192 user_select();
193 db_set("content-schema", CONTENT_SCHEMA, 0);
194 db_set("aux-schema", AUX_SCHEMA_MAX, 0);
195 db_set("rebuilt", get_version(), 0);
@@ -221,14 +247,14 @@
221 g.xlinkClusterOnly = 0;
222 verify_cancel();
223 db_end_transaction(0);
224 db_close(1);
225 if( nErr ){
226 file_delete(g.argv[3]);
227 fossil_fatal("server returned an error - clone aborted");
228 }
229 db_open_repository(g.argv[3]);
230 }
231 db_begin_transaction();
232 fossil_print("Rebuilding repository meta-data...\n");
233 rebuild_db(0, 1, 0);
234 if( !noCompress ){
@@ -247,10 +273,24 @@
247 db_protect_pop();
248 fossil_print("\nproject-id: %s\n", db_get("project-code", 0));
249 fossil_print("server-id: %s\n", db_get("server-code", 0));
250 zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
251 fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252 }
253
254 /*
255 ** If user chooses to use HTTP Authentication over unencrypted HTTP,
256 ** remember decision. Otherwise, if the URL is being changed and no
257
--- src/clone.c
+++ src/clone.c
@@ -80,15 +80,17 @@
80
81
82 /*
83 ** COMMAND: clone
84 **
85 ** Usage: %fossil clone ?OPTIONS? URI ?FILENAME?
86 **
87 ** Make a clone of a repository specified by URI in the local
88 ** file named FILENAME. If FILENAME is omitted, then an appropriate
89 ** filename is deduced from last element of the path in the URL.
90 **
91 ** URI may be one of the following forms ([...] denotes optional elements):
92 **
93 ** * HTTP/HTTPS protocol:
94 **
95 ** http[s]://[userid[:password]@]host[:port][/path]
96 **
@@ -98,36 +100,43 @@
100 **
101 ** * Filesystem:
102 **
103 ** [file://]path/to/repo.fossil
104 **
 
 
 
 
105 ** For ssh and filesystem, path must have an extra leading
106 ** '/' to use an absolute path.
107 **
108 ** Use %HH escapes for special characters in the userid and
109 ** password. For example "%40" in place of "@", "%2f" in place
110 ** of "/", and "%3a" in place of ":".
111 **
112 ** Note that in Fossil (in contrast to some other DVCSes) a repository
113 ** is distinct from a checkout. Cloning a repository is not the same thing
114 ** as opening a repository. This command always clones the repository. This
115 ** command might also open the repository, but only if the --no-open option
116 ** is omitted and either the --workdir option is included or the FILENAME
117 ** argument is omitted. Use the separate [[open]] command to open a
118 ** repository that was previously cloned and already exists on the
119 ** local machine.
120 **
121 ** By default, the current login name is used to create the default
122 ** admin user for the new clone. This can be overridden using
123 ** the -A|--admin-user parameter.
124 **
125 ** Options:
126 ** --admin-user|-A USERNAME Make USERNAME the administrator
127 ** --httpauth|-B USER:PASS Add HTTP Basic Authorization to requests
128 ** --nocompress Omit extra delta compression
129 ** --no-open Clone only. Do not open a check-out.
130 ** --once Don't remember the URI.
131 ** --private Also clone private branches
132 ** --save-http-password Remember the HTTP password without asking
133 ** --ssh-command|-c SSH Use SSH as the "ssh" command
134 ** --ssl-identity FILENAME Use the SSL identity if requested by the server
135 ** -u|--unversioned Also sync unversioned content
136 ** -v|--verbose Show more statistics in output
137 ** --workdir DIR Also open a checkout in DIR
138 **
139 ** See also: [[init]], [[open]]
140 */
141 void clone_cmd(void){
142 char *zPassword;
@@ -135,10 +144,14 @@
144 const char *zHttpAuth; /* HTTP Authorization user:pass information */
145 int nErr = 0;
146 int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
147 int syncFlags = SYNC_CLONE;
148 int noCompress = find_option("nocompress",0,0)!=0;
149 int noOpen = find_option("no-open",0,0)!=0;
150 const char *zRepo = 0; /* Name of the new local repository file */
151 const char *zWorkDir = 0; /* Open in this director, if not zero */
152
153
154 /* Also clone private branches */
155 if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
156 if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
157 if( find_option("save-http-password",0,0)!=0 ){
@@ -147,49 +160,62 @@
160 }
161 if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE;
162 if( find_option("unversioned","u",0)!=0 ) syncFlags |= SYNC_UNVERSIONED;
163 zHttpAuth = find_option("httpauth","B",1);
164 zDefaultUser = find_option("admin-user","A",1);
165 zWorkDir = find_option("workdir", 0, 1);
166 clone_ssh_find_options();
167 url_proxy_options();
168
169 /* We should be done with options.. */
170 verify_all_options();
171
172 if( g.argc < 3 ){
173 usage("?OPTIONS? FILE-OR-URL ?NEW-REPOSITORY?");
174 }
175 db_open_config(0, 0);
176 zRepo = g.argc==4 ? g.argv[3] : 0;
177 if( zRepo!=0 && -1 != file_size(zRepo, ExtFILE) ){
178 fossil_fatal("file already exists: %s", zRepo);
179 }
 
180 url_parse(g.argv[2], urlFlags);
181 if( zRepo==0 ){
182 int i;
183 const char *z = file_tail(g.url.isFile ? g.url.name : g.url.path);
184 for(i=0; z[i] && z[i]!='.'; i++){}
185 if( zWorkDir==0 ){
186 zWorkDir = mprintf("./%.*s", i, z);
187 }
188 zRepo = mprintf("./%.*s.fossil", i, z);
189 if( -1 != file_size(zRepo, ExtFILE) ){
190 fossil_fatal("file already exists: %s", zRepo);
191 }
192 }
193 if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
194 if( g.url.isFile ){
195 file_copy(g.url.name, zRepo);
196 db_close(1);
197 db_open_repository(zRepo);
198 db_open_config(1,0);
199 db_record_repository_filename(zRepo);
200 url_remember();
201 if( !(syncFlags & SYNC_PRIVATE) ) delete_private_content();
202 shun_artifacts();
203 db_create_default_users(1, zDefaultUser);
204 if( zDefaultUser ){
205 g.zLogin = zDefaultUser;
206 }else{
207 g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'");
208 }
209 fossil_print("Repository cloned into %s\n", zRepo);
210 }else{
211 db_close_config();
212 db_create_repository(zRepo);
213 db_open_repository(zRepo);
214 db_open_config(0,0);
215 db_begin_transaction();
216 db_record_repository_filename(zRepo);
217 db_initial_setup(0, 0, zDefaultUser);
218 user_select();
219 db_set("content-schema", CONTENT_SCHEMA, 0);
220 db_set("aux-schema", AUX_SCHEMA_MAX, 0);
221 db_set("rebuilt", get_version(), 0);
@@ -221,14 +247,14 @@
247 g.xlinkClusterOnly = 0;
248 verify_cancel();
249 db_end_transaction(0);
250 db_close(1);
251 if( nErr ){
252 file_delete(zRepo);
253 fossil_fatal("server returned an error - clone aborted");
254 }
255 db_open_repository(zRepo);
256 }
257 db_begin_transaction();
258 fossil_print("Rebuilding repository meta-data...\n");
259 rebuild_db(0, 1, 0);
260 if( !noCompress ){
@@ -247,10 +273,24 @@
273 db_protect_pop();
274 fossil_print("\nproject-id: %s\n", db_get("project-code", 0));
275 fossil_print("server-id: %s\n", db_get("server-code", 0));
276 zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
277 fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
278 if( zWorkDir!=0 && zWorkDir[0]!=0 && !noOpen ){
279 char *azNew[6];
280 fossil_print("opening the new %s repository in directory %s...\n",
281 zRepo, zWorkDir);
282 azNew[0] = g.argv[0];
283 azNew[1] = "open";
284 azNew[2] = (char*)zRepo;
285 azNew[3] = "--workdir";
286 azNew[4] = (char*)zWorkDir;
287 azNew[5] = 0;
288 g.argv = azNew;
289 g.argc = 5;
290 cmd_open();
291 }
292 }
293
294 /*
295 ** If user chooses to use HTTP Authentication over unencrypted HTTP,
296 ** remember decision. Otherwise, if the URL is being changed and no
297

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button