Fossil SCM

fossil-scm / src / clone.c
Source Blame History 437 lines
dbda8d6… drh 1 /*
c19f34c… drh 2 ** Copyright (c) 2007 D. Richard Hipp
dbda8d6… drh 3 **
dbda8d6… drh 4 ** This program is free software; you can redistribute it and/or
c06edd2… drh 5 ** modify it under the terms of the Simplified BSD License (also
c06edd2… drh 6 ** known as the "2-Clause License" or "FreeBSD License".)
c06edd2… drh 7
dbda8d6… drh 8 ** This program is distributed in the hope that it will be useful,
c06edd2… drh 9 ** but without any warranty; without even the implied warranty of
c06edd2… drh 10 ** merchantability or fitness for a particular purpose.
dbda8d6… drh 11 **
dbda8d6… drh 12 ** Author contact information:
dbda8d6… drh 13 ** [email protected]
dbda8d6… drh 14 ** http://www.hwaci.com/drh/
dbda8d6… drh 15 **
dbda8d6… drh 16 *******************************************************************************
dbda8d6… drh 17 **
dbda8d6… drh 18 ** This file contains code used to clone a repository
dbda8d6… drh 19 */
dbda8d6… drh 20 #include "config.h"
dbda8d6… drh 21 #include "clone.h"
dbda8d6… drh 22 #include <assert.h>
dbda8d6… drh 23
034e887… drh 24 /*
2f98f66… drh 25 ** If there are public BLOBs that deltas from private BLOBs, then
2f98f66… drh 26 ** undeltify the public BLOBs so that the private BLOBs may be safely
2f98f66… drh 27 ** deleted.
034e887… drh 28 */
2f98f66… drh 29 void fix_private_blob_dependencies(int showWarning){
034e887… drh 30 Bag toUndelta;
034e887… drh 31 Stmt q;
034e887… drh 32 int rid;
034e887… drh 33
2f98f66… drh 34 /* Careful: We are about to delete all BLOB entries that are private.
034e887… drh 35 ** So make sure that any no public BLOBs are deltas from a private BLOB.
034e887… drh 36 ** Otherwise after the deletion, we won't be able to recreate the public
034e887… drh 37 ** BLOBs.
034e887… drh 38 */
034e887… drh 39 db_prepare(&q,
034e887… drh 40 "SELECT "
034e887… drh 41 " rid, (SELECT uuid FROM blob WHERE rid=delta.rid),"
034e887… drh 42 " srcid, (SELECT uuid FROM blob WHERE rid=delta.srcid)"
034e887… drh 43 " FROM delta"
034e887… drh 44 " WHERE srcid in private AND rid NOT IN private"
034e887… drh 45 );
034e887… drh 46 bag_init(&toUndelta);
034e887… drh 47 while( db_step(&q)==SQLITE_ROW ){
034e887… drh 48 int rid = db_column_int(&q, 0);
034e887… drh 49 const char *zId = db_column_text(&q, 1);
034e887… drh 50 int srcid = db_column_int(&q, 2);
034e887… drh 51 const char *zSrc = db_column_text(&q, 3);
2f98f66… drh 52 if( showWarning ){
2f98f66… drh 53 fossil_warning(
2f98f66… drh 54 "public artifact %S (%d) is a delta from private artifact %S (%d)",
2f98f66… drh 55 zId, rid, zSrc, srcid
2f98f66… drh 56 );
2f98f66… drh 57 }
034e887… drh 58 bag_insert(&toUndelta, rid);
034e887… drh 59 }
034e887… drh 60 db_finalize(&q);
034e887… drh 61 while( (rid = bag_first(&toUndelta))>0 ){
034e887… drh 62 content_undelta(rid);
034e887… drh 63 bag_remove(&toUndelta, rid);
034e887… drh 64 }
034e887… drh 65 bag_clear(&toUndelta);
2f98f66… drh 66 }
034e887… drh 67
2f98f66… drh 68 /*
2f98f66… drh 69 ** Delete all private content from a repository.
2f98f66… drh 70 */
2f98f66… drh 71 void delete_private_content(void){
2f98f66… drh 72 fix_private_blob_dependencies(1);
034e887… drh 73 db_multi_exec(
034e887… drh 74 "DELETE FROM blob WHERE rid IN private;"
db0c512… drh 75 "DELETE FROM delta WHERE rid IN private;"
034e887… drh 76 "DELETE FROM private;"
ba418ee… drh 77 "DROP TABLE IF EXISTS modreq;"
034e887… drh 78 );
034e887… drh 79 }
dbda8d6… drh 80
dbda8d6… drh 81
dbda8d6… drh 82 /*
dbda8d6… drh 83 ** COMMAND: clone
dbda8d6… drh 84 **
a8d7878… drh 85 ** Usage: %fossil clone ?OPTIONS? URI ?FILENAME?
b5354f1… drh 86 **
b5354f1… drh 87 ** Make a clone of a repository specified by URI in the local
a8d7878… drh 88 ** file named FILENAME. If FILENAME is omitted, then an appropriate
a8d7878… drh 89 ** filename is deduced from last element of the path in the URL.
a8d7878… drh 90 **
a8d7878… drh 91 ** URI may be one of the following forms ([...] denotes optional elements):
e58c76a… drh 92 **
e58c76a… drh 93 ** * HTTP/HTTPS protocol:
e58c76a… drh 94 **
e58c76a… drh 95 ** http[s]://[userid[:password]@]host[:port][/path]
e58c76a… drh 96 **
e58c76a… drh 97 ** * SSH protocol:
e58c76a… drh 98 **
e58c76a… drh 99 ** ssh://[userid@]host[:port]/path/to/repo.fossil[?fossil=path/fossil.exe]
e58c76a… drh 100 **
e58c76a… drh 101 ** * Filesystem:
e58c76a… drh 102 **
e58c76a… drh 103 ** [file://]path/to/repo.fossil
e58c76a… drh 104 **
a31a717… drh 105 ** For ssh and filesystem, path must have an extra leading
e58c76a… drh 106 ** '/' to use an absolute path.
e58c76a… drh 107 **
a31a717… drh 108 ** Use %HH escapes for special characters in the userid and
e58c76a… drh 109 ** password. For example "%40" in place of "@", "%2f" in place
e58c76a… drh 110 ** of "/", and "%3a" in place of ":".
e58c76a… drh 111 **
a8d7878… drh 112 ** Note that in Fossil (in contrast to some other DVCSes) a repository
bc36fdc… danield 113 ** is distinct from a check-out. Cloning a repository is not the same thing
a8d7878… drh 114 ** as opening a repository. This command always clones the repository. This
a8d7878… drh 115 ** command might also open the repository, but only if the --no-open option
a8d7878… drh 116 ** is omitted and either the --workdir option is included or the FILENAME
a8d7878… drh 117 ** argument is omitted. Use the separate [[open]] command to open a
a8d7878… drh 118 ** repository that was previously cloned and already exists on the
a8d7878… drh 119 ** local machine.
a8d7878… drh 120 **
a31a717… drh 121 ** By default, the current login name is used to create the default
a8d7878… drh 122 ** admin user for the new clone. This can be overridden using
a8d7878… drh 123 ** the -A|--admin-user parameter.
14c19fb… drh 124 **
14c19fb… drh 125 ** Options:
7f3c728… jamsek 126 ** -A|--admin-user USERNAME Make USERNAME the administrator
7f3c728… jamsek 127 ** -B|--httpauth USER:PASS Add HTTP Basic Authorization to requests
e1d54eb… drh 128 ** --nested Allow opening a repository inside an opened
bc36fdc… danield 129 ** check-out
96d0a4b… drh 130 ** --nocompress Omit extra delta compression
a8d7878… drh 131 ** --no-open Clone only. Do not open a check-out.
b5354f1… drh 132 ** --once Don't remember the URI.
080ab8c… jan.nijtmans 133 ** --private Also clone private branches
6d4cd32… mgagnon 134 ** --proxy PROXY Use the specified HTTP proxy
22517ba… drh 135 ** --save-http-password Remember the HTTP password without asking
2512d2d… km 136 ** -c|--ssh-command SSH Use SSH as the "ssh" command
26d0c20… drh 137 ** --ssl-identity FILENAME Use the SSL identity if requested by the server
505d9d4… drh 138 ** --transport-command CMD Use CMD to move messages to the server and back
a5d8548… drh 139 ** -u|--unversioned Also sync unversioned content
a5d8548… drh 140 ** -v|--verbose Show more statistics in output
bc36fdc… danield 141 ** --workdir DIR Also open a check-out in DIR
a8e33fb… drh 142 ** --xverbose Extra debugging output
dbda8d6… drh 143 **
71992d0… drh 144 ** See also: [[init]], [[open]]
dbda8d6… drh 145 */
dbda8d6… drh 146 void clone_cmd(void){
0c6ea0d… drh 147 char *zPassword;
14c19fb… drh 148 const char *zDefaultUser; /* Optional name of the default user */
5d536c5… drh 149 const char *zHttpAuth; /* HTTP Authorization user:pass information */
f6263ed… drh 150 int nErr = 0;
ff159bf… andybradford 151 int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
5e7d3ef… drh 152 int syncFlags = SYNC_CLONE;
96d0a4b… drh 153 int noCompress = find_option("nocompress",0,0)!=0;
a8d7878… drh 154 int noOpen = find_option("no-open",0,0)!=0;
f3d115d… mgagnon 155 int allowNested = find_option("nested",0,0)!=0; /* Used by open */
a8d7878… drh 156 const char *zRepo = 0; /* Name of the new local repository file */
f3d115d… mgagnon 157 const char *zWorkDir = 0; /* Open in this directory, if not zero */
a8d7878… drh 158
dbb5e2d… drh 159
5e7d3ef… drh 160 /* Also clone private branches */
5e7d3ef… drh 161 if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
ff159bf… andybradford 162 if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
22517ba… drh 163 if( find_option("save-http-password",0,0)!=0 ){
421e6bb… drh 164 urlFlags &= ~URL_PROMPT_PW;
421e6bb… drh 165 urlFlags |= URL_REMEMBER_PW;
421e6bb… drh 166 }
a5d8548… drh 167 if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE;
a8e33fb… drh 168 if( find_option("xverbose",0,0)!=0) syncFlags |= SYNC_XVERBOSE;
cdd58b1… wyoung 169 if( find_option("unversioned","u",0)!=0 ){
cdd58b1… wyoung 170 syncFlags |= SYNC_UNVERSIONED;
cdd58b1… wyoung 171 if( syncFlags & SYNC_VERBOSE ){
cdd58b1… wyoung 172 syncFlags |= SYNC_UV_TRACE;
cdd58b1… wyoung 173 }
cdd58b1… wyoung 174 }
5d536c5… drh 175 zHttpAuth = find_option("httpauth","B",1);
cc421c0… andybradford 176 zDefaultUser = find_option("admin-user","A",1);
a8d7878… drh 177 zWorkDir = find_option("workdir", 0, 1);
dbb5e2d… drh 178 clone_ssh_find_options();
dbb5e2d… drh 179 url_proxy_options();
14b3f48… drh 180 g.zHttpCmd = find_option("transport-command",0,1);
080ab8c… jan.nijtmans 181
74ac0c9… drh 182 /* We should be done with options.. */
74ac0c9… drh 183 verify_all_options();
74ac0c9… drh 184
a8d7878… drh 185 if( g.argc < 3 ){
a8d7878… drh 186 usage("?OPTIONS? FILE-OR-URL ?NEW-REPOSITORY?");
b06cd63… mistachkin 187 }
b06cd63… mistachkin 188 db_open_config(0, 0);
f978fcd… drh 189 if( g.argc==4 ){
f978fcd… drh 190 zRepo = g.argv[3];
f978fcd… drh 191 }else{
f978fcd… drh 192 char *zBase = url_to_repo_basename(g.argv[2]);
f978fcd… drh 193 if( zBase==0 ){
4fa02af… drh 194 fossil_fatal(
4fa02af… drh 195 "unable to guess a repository name from the url \"%s\".\n"
4fa02af… drh 196 "give the repository filename as an additional argument.",
4fa02af… drh 197 g.argv[2]);
4fa02af… drh 198 }
f978fcd… drh 199 zRepo = mprintf("./%s.fossil", zBase);
4fa02af… drh 200 if( zWorkDir==0 ){
f978fcd… drh 201 zWorkDir = mprintf("./%s", zBase);
4fa02af… drh 202 }
f978fcd… drh 203 fossil_free(zBase);
275da70… danield 204 }
f978fcd… drh 205 if( -1 != file_size(zRepo, ExtFILE) ){
f978fcd… drh 206 fossil_fatal("file already exists: %s", zRepo);
f3d115d… mgagnon 207 }
bc36fdc… danield 208 /* Fail before clone if open will fail because inside an open check-out */
f3d115d… mgagnon 209 if( zWorkDir!=0 && zWorkDir[0]!=0 && !noOpen ){
f3d115d… mgagnon 210 if( db_open_local_v2(0, allowNested) ){
f3d115d… mgagnon 211 fossil_fatal("there is already an open tree at %s", g.zLocalRoot);
f3d115d… mgagnon 212 }
4fa02af… drh 213 }
f978fcd… drh 214 url_parse(g.argv[2], urlFlags);
5fdad9b… drh 215 if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
5fdad9b… drh 216 if( g.url.isFile ){
a8d7878… drh 217 file_copy(g.url.name, zRepo);
c2f5dbe… drh 218 db_close(1);
a8d7878… drh 219 db_open_repository(zRepo);
9d2b7ca… drh 220 db_open_config(1,0);
a8d7878… drh 221 db_record_repository_filename(zRepo);
6d6740d… drh 222 url_remember();
5e7d3ef… drh 223 if( !(syncFlags & SYNC_PRIVATE) ) delete_private_content();
02a584f… drh 224 shun_artifacts();
d86201d… drh 225 db_create_default_users(1, zDefaultUser);
d86201d… drh 226 if( zDefaultUser ){
d86201d… drh 227 g.zLogin = zDefaultUser;
d86201d… drh 228 }else{
d86201d… drh 229 g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'");
02a584f… drh 230 }
a8d7878… drh 231 fossil_print("Repository cloned into %s\n", zRepo);
9236f0c… drh 232 }else{
10f753a… drh 233 db_close_config();
a8d7878… drh 234 db_create_repository(zRepo);
a8d7878… drh 235 db_open_repository(zRepo);
10f753a… drh 236 db_open_config(0,0);
e1962ef… drh 237 db_begin_transaction();
a8d7878… drh 238 db_record_repository_filename(zRepo);
a6e2ceb… drh 239 db_initial_setup(0, 0, zDefaultUser);
9236f0c… drh 240 user_select();
9236f0c… drh 241 db_set("content-schema", CONTENT_SCHEMA, 0);
5dd8b2d… drh 242 db_set("aux-schema", AUX_SCHEMA_MAX, 0);
c0242ad… mistachkin 243 db_set("rebuilt", get_version(), 0);
e92133a… drh 244 db_unset("hash-policy", 0);
5d536c5… drh 245 remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, g.argv[2]);
6d6740d… drh 246 url_remember();
9a0c995… drh 247 if( g.zSSLIdentity!=0 ){
9a0c995… drh 248 /* If the --ssl-identity option was specified, store it as a setting */
9a0c995… drh 249 Blob fn;
9a0c995… drh 250 blob_zero(&fn);
135ed93… drh 251 file_canonical_name(g.zSSLIdentity, &fn, 0);
e363683… drh 252 db_unprotect(PROTECT_ALL);
9a0c995… drh 253 db_set("ssl-identity", blob_str(&fn), 0);
e363683… drh 254 db_protect_pop();
9a0c995… drh 255 blob_reset(&fn);
9a0c995… drh 256 }
f741baa… drh 257 db_unprotect(PROTECT_CONFIG);
9236f0c… drh 258 db_multi_exec(
1654456… drh 259 "REPLACE INTO config(name,value,mtime)"
1654456… drh 260 " VALUES('server-code', lower(hex(randomblob(20))), now());"
14b8475… drh 261 "DELETE FROM config WHERE name='project-code';"
9236f0c… drh 262 );
f741baa… drh 263 db_protect_pop();
9236f0c… drh 264 url_enable_proxy(0);
dbb5e2d… drh 265 clone_ssh_db_set_options();
cc31b46… drh 266 url_get_password_if_needed();
9236f0c… drh 267 g.xlinkClusterOnly = 1;
0cd5589… drh 268 nErr = client_sync(syncFlags,CONFIGSET_ALL,0,0,0);
9236f0c… drh 269 g.xlinkClusterOnly = 0;
9236f0c… drh 270 verify_cancel();
9236f0c… drh 271 db_end_transaction(0);
c2f5dbe… drh 272 db_close(1);
f6263ed… drh 273 if( nErr ){
a8d7878… drh 274 file_delete(zRepo);
a8e33fb… drh 275 if( g.fHttpTrace ){
a8e33fb… drh 276 fossil_fatal(
a8e33fb… drh 277 "server returned an error - clone aborted\n\n%s",
a8e33fb… drh 278 http_last_trace_reply()
a8e33fb… drh 279 );
a8e33fb… drh 280 }else{
a8e33fb… drh 281 fossil_fatal(
a8e33fb… drh 282 "server returned an error - clone aborted\n"
a8e33fb… drh 283 "Rerun using --httptrace for more detail"
a8e33fb… drh 284 );
a8e33fb… drh 285 }
e1962ef… drh 286 }
a8d7878… drh 287 db_open_repository(zRepo);
e1962ef… drh 288 }
e1962ef… drh 289 db_begin_transaction();
55a5b70… drh 290 if( db_exists("SELECT 1 FROM delta WHERE srcId IN phantom") ){
55a5b70… drh 291 fossil_fatal("there are unresolved deltas -"
55a5b70… drh 292 " the clone is probably incomplete and unusable.");
55a5b70… drh 293 }
e1962ef… drh 294 fossil_print("Rebuilding repository meta-data...\n");
298ccff… stephan 295 rebuild_db(1, 0);
e1962ef… drh 296 if( !noCompress ){
59e21eb… drh 297 int nDelta = 0;
59e21eb… drh 298 i64 nByte;
e1962ef… drh 299 fossil_print("Extra delta compression... "); fflush(stdout);
59e21eb… drh 300 nByte = extra_deltification(&nDelta);
dd6a88d… drh 301 if( nDelta==1 ){
dd6a88d… drh 302 fossil_print("1 delta saves %,lld bytes\n", nByte);
dd6a88d… drh 303 }else if( nDelta>1 ){
59e21eb… drh 304 fossil_print("%d deltas save %,lld bytes\n", nDelta, nByte);
59e21eb… drh 305 }else{
dd6a88d… drh 306 fossil_print("none found\n");
59e21eb… drh 307 }
96d0a4b… drh 308 }
35c2555… drh 309 db_end_transaction(0);
96d0a4b… drh 310 fossil_print("Vacuuming the database... "); fflush(stdout);
10f5fc6… jan.nijtmans 311 if( db_int(0, "PRAGMA page_count")>1000
35c2555… drh 312 && db_int(0, "PRAGMA page_size")<8192 ){
35c2555… drh 313 db_multi_exec("PRAGMA page_size=8192;");
35c2555… drh 314 }
f741baa… drh 315 db_unprotect(PROTECT_ALL);
35c2555… drh 316 db_multi_exec("VACUUM");
f741baa… drh 317 db_protect_pop();
35c2555… drh 318 fossil_print("\nproject-id: %s\n", db_get("project-code", 0));
11ba4bd… jan.nijtmans 319 fossil_print("server-id: %s\n", db_get("server-code", 0));
d8ec765… drh 320 zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
d8ec765… drh 321 fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
593e801… preben 322 hash_user_password(g.zLogin);
a8d7878… drh 323 if( zWorkDir!=0 && zWorkDir[0]!=0 && !noOpen ){
ebd604f… drh 324 Blob cmd;
f3d115d… mgagnon 325 fossil_print("opening the new %s repository in directory %s...\n",
f3d115d… mgagnon 326 zRepo, zWorkDir);
ebd604f… drh 327 blob_init(&cmd, 0, 0);
4f83d06… drh 328 blob_append_escaped_arg(&cmd, g.nameOfExe, 1);
ebd604f… drh 329 blob_append(&cmd, " open ", -1);
4f83d06… drh 330 blob_append_escaped_arg(&cmd, zRepo, 1);
160bd67… drh 331 blob_append(&cmd, " --nosync --workdir ", -1);
4f83d06… drh 332 blob_append_escaped_arg(&cmd, zWorkDir, 1);
f3d115d… mgagnon 333 if( allowNested ){
ebd604f… drh 334 blob_append(&cmd, " --nested", -1);
ebd604f… drh 335 }
ebd604f… drh 336 fossil_system(blob_str(&cmd));
ebd604f… drh 337 blob_reset(&cmd);
a8d7878… drh 338 }
5d536c5… drh 339 }
5d536c5… drh 340
5d536c5… drh 341 /*
5d536c5… drh 342 ** If user chooses to use HTTP Authentication over unencrypted HTTP,
080ab8c… jan.nijtmans 343 ** remember decision. Otherwise, if the URL is being changed and no
5d536c5… drh 344 ** preference has been indicated, err on the safe side and revert the
5d536c5… drh 345 ** decision. Set the global preference if the URL is not being changed.
5d536c5… drh 346 */
5d536c5… drh 347 void remember_or_get_http_auth(
5d536c5… drh 348 const char *zHttpAuth, /* Credentials in the form "user:password" */
5d536c5… drh 349 int fRemember, /* True to remember credentials for later reuse */
5d536c5… drh 350 const char *zUrl /* URL for which these credentials apply */
5d536c5… drh 351 ){
5d536c5… drh 352 if( zHttpAuth && zHttpAuth[0] ){
4c3e172… danield 353 g.zHttpAuth = fossil_strdup(zHttpAuth);
5d536c5… drh 354 }
5d536c5… drh 355 if( fRemember ){
5d536c5… drh 356 if( g.zHttpAuth && g.zHttpAuth[0] ){
5d536c5… drh 357 set_httpauth(g.zHttpAuth);
5d536c5… drh 358 }else if( zUrl && zUrl[0] ){
0a5d0e1… drh 359 db_unset_mprintf(0, "http-auth:%s", g.url.canonical);
5d536c5… drh 360 }else{
5d536c5… drh 361 g.zHttpAuth = get_httpauth();
5d536c5… drh 362 }
5d536c5… drh 363 }else if( g.zHttpAuth==0 && zUrl==0 ){
5d536c5… drh 364 g.zHttpAuth = get_httpauth();
5d536c5… drh 365 }
5d536c5… drh 366 }
5d536c5… drh 367
5d536c5… drh 368 /*
5d536c5… drh 369 ** Get the HTTP Authorization preference from db.
5d536c5… drh 370 */
5d536c5… drh 371 char *get_httpauth(void){
5fdad9b… drh 372 char *zKey = mprintf("http-auth:%s", g.url.canonical);
3fc62dd… stephan 373 char * rc = unobscure(db_get(zKey, 0));
5d536c5… drh 374 free(zKey);
3fc62dd… stephan 375 return rc;
5d536c5… drh 376 }
5d536c5… drh 377
5d536c5… drh 378 /*
5d536c5… drh 379 ** Set the HTTP Authorization preference in db.
5d536c5… drh 380 */
5d536c5… drh 381 void set_httpauth(const char *zHttpAuth){
0a5d0e1… drh 382 db_set_mprintf(obscure(zHttpAuth), 0, "http-auth:%s", g.url.canonical);
dbb5e2d… drh 383 }
dbb5e2d… drh 384
dbb5e2d… drh 385 /*
dbb5e2d… drh 386 ** Look for SSH clone command line options and setup in globals.
dbb5e2d… drh 387 */
dbb5e2d… drh 388 void clone_ssh_find_options(void){
dbb5e2d… drh 389 const char *zSshCmd; /* SSH command string */
dbb5e2d… drh 390
dbb5e2d… drh 391 zSshCmd = find_option("ssh-command","c",1);
dbb5e2d… drh 392 if( zSshCmd && zSshCmd[0] ){
4c3e172… danield 393 g.zSshCmd = fossil_strdup(zSshCmd);
dbb5e2d… drh 394 }
dbb5e2d… drh 395 }
dbb5e2d… drh 396
dbb5e2d… drh 397 /*
080ab8c… jan.nijtmans 398 ** Set SSH options discovered in global variables (set from command line
dbb5e2d… drh 399 ** options).
dbb5e2d… drh 400 */
dbb5e2d… drh 401 void clone_ssh_db_set_options(void){
dbb5e2d… drh 402 if( g.zSshCmd && g.zSshCmd[0] ){
d700f5f… wyoung 403 db_unprotect(PROTECT_ALL);
dbb5e2d… drh 404 db_set("ssh-command", g.zSshCmd, 0);
d700f5f… wyoung 405 db_protect_pop();
c5fea12… drh 406 }
c5fea12… drh 407 }
c5fea12… drh 408
c5fea12… drh 409 /*
6ce705b… drh 410 ** WEBPAGE: howtoclone
c5fea12… drh 411 **
6ce705b… drh 412 ** Provide instructions on how to clone this repository.
c5fea12… drh 413 */
6ce705b… drh 414 void howtoclone_page(void){
c5fea12… drh 415 login_check_credentials();
57f1e87… drh 416 cgi_check_for_malice();
6ce705b… drh 417 style_header("How To Clone This Repository");
c5fea12… drh 418 if( !g.perm.Clone ){
c5fea12… drh 419 @ <p>You are not authorized to clone this repository.
c5fea12… drh 420 if( g.zLogin==0 || g.zLogin[0]==0 ){
c5fea12… drh 421 @ Maybe you would be able to clone if you
ad5999a… drh 422 @ %z(href("%R/login"))logged in</a>.
c5fea12… drh 423 }else{
c5fea12… drh 424 @ Contact the site administrator and ask them to give
c5fea12… drh 425 @ you "Clone" privileges in order to clone.
c5fea12… drh 426 }
c5fea12… drh 427 }else{
c5fea12… drh 428 const char *zNm = db_get("short-project-name","clone");
6ce705b… drh 429 @ <p>Clone this repository by running a command like the following:
c5fea12… drh 430 @ <blockquote><pre>
c5fea12… drh 431 @ fossil clone %s(g.zBaseURL) %h(zNm).fossil
c5fea12… drh 432 @ </pre></blockquote>
6ce705b… drh 433 @ <p>Do a web search for "fossil clone" or similar to find additional
6ce705b… drh 434 @ information about using a cloned Fossil repository.
dbb5e2d… drh 435 }
112c713… drh 436 style_finish_page();
dbda8d6… drh 437 }

Keyboard Shortcuts

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