Fossil SCM

fossil-scm / src / sync.c
Source Blame History 928 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 push, pull, and sync a repository
dbda8d6… drh 19 */
dbda8d6… drh 20 #include "config.h"
dbda8d6… drh 21 #include "sync.h"
dbda8d6… drh 22 #include <assert.h>
dbda8d6… drh 23
1570857… drh 24 /*
6b4a04d… drh 25 ** Explain what type of sync operation is about to occur
6b4a04d… drh 26 */
6b4a04d… drh 27 static void sync_explain(unsigned syncFlags){
6c9d32a… george 28 if( (g.url.isAlias || g.url.useProxy) && (syncFlags & SYNC_QUIET)==0 ){
a791d5e… mgagnon 29 const char *url;
a791d5e… mgagnon 30 if( g.url.useProxy ){
a791d5e… mgagnon 31 url = g.url.proxyUrlCanonical;
a791d5e… mgagnon 32 }else{
a791d5e… mgagnon 33 url = g.url.canonical;
a791d5e… mgagnon 34 }
6b4a04d… drh 35 if( (syncFlags & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){
a791d5e… mgagnon 36 fossil_print("Sync with %s\n", url);
6b4a04d… drh 37 }else if( syncFlags & SYNC_PUSH ){
a791d5e… mgagnon 38 fossil_print("Push to %s\n", url);
6b4a04d… drh 39 }else if( syncFlags & SYNC_PULL ){
a791d5e… mgagnon 40 fossil_print("Pull from %s\n", url);
8fa8fe8… drh 41 }else if( syncFlags & SYNC_PING ){
8fa8fe8… drh 42 fossil_print("Ping %s\n", url);
6b4a04d… drh 43 }
6b4a04d… drh 44 }
6b4a04d… drh 45 }
6b4a04d… drh 46
6b4a04d… drh 47
6b4a04d… drh 48 /*
6b4a04d… drh 49 ** Call client_sync() one or more times in order to complete a
6b4a04d… drh 50 ** sync operation. Usually, client_sync() is called only once, though
6b4a04d… drh 51 ** is can be called multiple times if the SYNC_ALLURL flags is set.
6b4a04d… drh 52 */
6b4a04d… drh 53 static int client_sync_all_urls(
6b4a04d… drh 54 unsigned syncFlags, /* Mask of SYNC_* flags */
6b4a04d… drh 55 unsigned configRcvMask, /* Receive these configuration items */
6b4a04d… drh 56 unsigned configSendMask, /* Send these configuration items */
6b4a04d… drh 57 const char *zAltPCode /* Alternative project code (usually NULL) */
6b4a04d… drh 58 ){
38dad38… drh 59 int nErr = 0; /* Number of errors seen */
0cd5589… drh 60 int nOther; /* Number of extra remote URLs */
0cd5589… drh 61 char **azOther; /* Text of extra remote URLs */
0cd5589… drh 62 int i; /* Loop counter */
0cd5589… drh 63 int iEnd; /* Loop termination point */
0cd5589… drh 64 int nextIEnd; /* Loop termination point for next pass */
0cd5589… drh 65 int iPass; /* Which pass through the remotes. 0 or 1 */
0cd5589… drh 66 int nPass; /* Number of passes to make. 1 or 2 */
0cd5589… drh 67 Stmt q; /* An SQL statement */
0cd5589… drh 68 UrlData baseUrl; /* Saved parse of the default remote */
6b4a04d… drh 69
6b4a04d… drh 70 sync_explain(syncFlags);
0cd5589… drh 71 if( (syncFlags & SYNC_ALLURL)==0 ){
0cd5589… drh 72 /* Common-case: Only sync with the remote identified by g.url */
0cd5589… drh 73 nErr = client_sync(syncFlags, configRcvMask, configSendMask, zAltPCode, 0);
0cd5589… drh 74 if( nErr==0 ) url_remember();
0cd5589… drh 75 return nErr;
0cd5589… drh 76 }
0cd5589… drh 77
0cd5589… drh 78 /* If we reach this point, it means we want to sync with all remotes */
0cd5589… drh 79 memset(&baseUrl, 0, sizeof(baseUrl));
0cd5589… drh 80 url_move_parse(&baseUrl, &g.url);
6b4a04d… drh 81 nOther = 0;
6b4a04d… drh 82 azOther = 0;
6b4a04d… drh 83 db_prepare(&q,
6b4a04d… drh 84 "SELECT substr(name,10) FROM config"
6b4a04d… drh 85 " WHERE name glob 'sync-url:*'"
6b4a04d… drh 86 " AND value<>(SELECT value FROM config WHERE name='last-sync-url')"
6b4a04d… drh 87 );
6b4a04d… drh 88 while( db_step(&q)==SQLITE_ROW ){
6b4a04d… drh 89 const char *zUrl = db_column_text(&q, 0);
6b4a04d… drh 90 azOther = fossil_realloc(azOther, sizeof(*azOther)*(nOther+1));
6b4a04d… drh 91 azOther[nOther++] = fossil_strdup(zUrl);
6b4a04d… drh 92 }
6b4a04d… drh 93 db_finalize(&q);
0cd5589… drh 94 iEnd = nOther+1;
0cd5589… drh 95 nextIEnd = 0;
0cd5589… drh 96 nPass = 1 + ((syncFlags & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL));
0cd5589… drh 97 for(iPass=0; iPass<nPass; iPass++){
0cd5589… drh 98 for(i=0; i<iEnd; i++){
0cd5589… drh 99 int rc;
0cd5589… drh 100 int nRcvd;
0cd5589… drh 101 if( i==0 ){
0cd5589… drh 102 url_move_parse(&g.url, &baseUrl); /* Load canonical URL */
0cd5589… drh 103 }else{
0cd5589… drh 104 /* Load an auxiliary remote URL */
0cd5589… drh 105 url_parse(azOther[i-1],
0cd5589… drh 106 URL_PROMPT_PW|URL_ASK_REMEMBER_PW|URL_USE_CONFIG);
0cd5589… drh 107 }
0cd5589… drh 108 if( i>0 || iPass>0 ) sync_explain(syncFlags);
0cd5589… drh 109 rc = client_sync(syncFlags, configRcvMask, configSendMask,
0cd5589… drh 110 zAltPCode, &nRcvd);
0cd5589… drh 111 if( nRcvd>0 ){
0cd5589… drh 112 /* If new artifacts were received, we want to repeat all prior
0cd5589… drh 113 ** remotes on the second pass */
0cd5589… drh 114 nextIEnd = i;
0cd5589… drh 115 }
0cd5589… drh 116 nErr += rc;
0cd5589… drh 117 if( rc==0 && iPass==0 ){
0cd5589… drh 118 if( i==0 ){
0cd5589… drh 119 url_remember();
0cd5589… drh 120 }else if( (g.url.flags & URL_REMEMBER_PW)!=0 ){
0cd5589… drh 121 char *zKey = mprintf("sync-pw:%s", azOther[i-1]);
0cd5589… drh 122 char *zPw = obscure(g.url.passwd);
0cd5589… drh 123 if( zPw && zPw[0] ){
0cd5589… drh 124 db_set(zKey/*works-like:""*/, zPw, 0);
0cd5589… drh 125 }
0cd5589… drh 126 fossil_free(zPw);
0cd5589… drh 127 fossil_free(zKey);
0cd5589… drh 128 }
0cd5589… drh 129 }
0cd5589… drh 130 if( i==0 ){
0cd5589… drh 131 url_move_parse(&baseUrl, &g.url); /* Don't forget canonical URL */
0cd5589… drh 132 }else{
0cd5589… drh 133 url_unparse(&g.url); /* Delete auxiliary URL parses */
0cd5589… drh 134 }
0cd5589… drh 135 }
0cd5589… drh 136 iEnd = nextIEnd;
0cd5589… drh 137 }
0cd5589… drh 138 for(i=0; i<nOther; i++){
6b4a04d… drh 139 fossil_free(azOther[i]);
6b4a04d… drh 140 azOther[i] = 0;
6b4a04d… drh 141 }
6b4a04d… drh 142 fossil_free(azOther);
0cd5589… drh 143 url_move_parse(&g.url, &baseUrl); /* Restore the canonical URL parse */
6b4a04d… drh 144 return nErr;
6b4a04d… drh 145 }
6b4a04d… drh 146
6b4a04d… drh 147
6b4a04d… drh 148 /*
7c0f4ec… jan.nijtmans 149 ** If the repository is configured for autosyncing, then do an
0d5251d… drh 150 ** autosync. Bits of the "flags" parameter determine details of behavior:
0d5251d… drh 151 **
0d5251d… drh 152 ** SYNC_PULL Pull content from the server to the local repo
0d5251d… drh 153 ** SYNC_PUSH Push content from local up to the server
bc36fdc… danield 154 ** SYNC_CKIN_LOCK Take a check-in lock on the current check-out.
0d5251d… drh 155 ** SYNC_VERBOSE Extra output
0cc4875… drh 156 **
0cc4875… drh 157 ** Return the number of errors.
0d5251d… drh 158 **
0d5251d… drh 159 ** The autosync setting can be a boolean or "pullonly". No autosync
0d5251d… drh 160 ** is attempted if the autosync setting is off, and only auto-pull is
0d5251d… drh 161 ** attempted if autosync is set to "pullonly". The check-in lock is
0d5251d… drh 162 ** not acquired unless autosync is set to "on".
0d5251d… drh 163 **
0d5251d… drh 164 ** If dont-push setting is true, that is the same as having autosync
0d5251d… drh 165 ** set to pullonly.
0cc4875… drh 166 */
346e457… drh 167 static int autosync(int flags, const char *zSubsys){
a3161f5… drh 168 const char *zAutosync;
0cc4875… drh 169 int rc;
515814f… drh 170 int configSync = 0; /* configuration changes transferred */
390b414… drh 171 if( g.fNoSync ){
0cc4875… drh 172 return 0;
0cc4875… drh 173 }
346e457… drh 174 zAutosync = db_get_for_subsystem("autosync", zSubsys);
eb804dc… drh 175 if( zAutosync==0 ) zAutosync = "on"; /* defend against misconfig */
0d5251d… drh 176 if( is_false(zAutosync) ) return 0;
275da70… danield 177 if( db_get_boolean("dont-push",0)
19d7c5f… drh 178 || sqlite3_strglob("*pull*", zAutosync)==0
19d7c5f… drh 179 ){
0d5251d… drh 180 flags &= ~SYNC_CKIN_LOCK;
0d5251d… drh 181 if( flags & SYNC_PUSH ) return 0;
0d5251d… drh 182 }
241ade8… drh 183 if( find_option("verbose","v",0)!=0 ) flags |= SYNC_VERBOSE;
0aff8d8… drh 184 url_parse(0, URL_REMEMBER|URL_USE_CONFIG);
080ab8c… jan.nijtmans 185 if( g.url.protocol==0 ) return 0;
5fdad9b… drh 186 if( g.url.user!=0 && g.url.passwd==0 ){
5fdad9b… drh 187 g.url.passwd = unobscure(db_get("last-sync-pw", 0));
5fdad9b… drh 188 g.url.flags |= URL_PROMPT_PW;
dbb5e2d… drh 189 url_prompt_for_password();
dbb5e2d… drh 190 }
5d536c5… drh 191 g.zHttpAuth = get_httpauth();
19d7c5f… drh 192 if( sqlite3_strglob("*all*", zAutosync)==0 ){
241ade8… drh 193 rc = client_sync_all_urls(flags|SYNC_ALLURL, configSync, 0, 0);
241ade8… drh 194 }else{
241ade8… drh 195 url_remember();
241ade8… drh 196 sync_explain(flags);
241ade8… drh 197 url_enable_proxy("via proxy: ");
0cd5589… drh 198 rc = client_sync(flags, configSync, 0, 0, 0);
241ade8… drh 199 }
76bc297… andybradford 200 return rc;
76bc297… andybradford 201 }
76bc297… andybradford 202
76bc297… andybradford 203 /*
76bc297… andybradford 204 ** This routine will try a number of times to perform autosync with a
9445f8a… drh 205 ** 0.5 second sleep between attempts. The number of attempts is determined
9445f8a… drh 206 ** by the "autosync-tries" setting, which defaults to 1.
d685096… drh 207 **
d685096… drh 208 ** Return zero on success and non-zero on a failure. If failure occurs
d685096… drh 209 ** and doPrompt flag is true, ask the user if they want to continue, and
d685096… drh 210 ** if they answer "yes" then return zero in spite of the failure.
76bc297… andybradford 211 */
346e457… drh 212 int autosync_loop(int flags, int doPrompt, const char *zSubsystem){
76bc297… andybradford 213 int n = 0;
76bc297… andybradford 214 int rc = 0;
9445f8a… drh 215 int nTries = db_get_int("autosync-tries", 1);
b9fd594… drh 216 if( (flags & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL)
b9fd594… drh 217 && db_get_boolean("uv-sync",0)
b9fd594… drh 218 ){
b9fd594… drh 219 flags |= SYNC_UNVERSIONED;
b9fd594… drh 220 }
346e457… drh 221 if( nTries<1 ) nTries = 1;
346e457… drh 222 while( (n==0 || n<nTries) && (rc=autosync(flags, zSubsystem)) ){
2f9c2ea… andybradford 223 if( rc ){
40d5560… mistachkin 224 if( ++n<nTries ){
2f9c2ea… andybradford 225 fossil_warning("Autosync failed, making another attempt.");
2f9c2ea… andybradford 226 sqlite3_sleep(500);
2f9c2ea… andybradford 227 }else{
2f9c2ea… andybradford 228 fossil_warning("Autosync failed.");
2f9c2ea… andybradford 229 }
2f9c2ea… andybradford 230 }
d685096… drh 231 }
d685096… drh 232 if( rc && doPrompt ){
d685096… drh 233 Blob ans;
d685096… drh 234 char cReply;
d685096… drh 235 prompt_user("continue in spite of sync failure (y/N)? ", &ans);
d685096… drh 236 cReply = blob_str(&ans)[0];
d685096… drh 237 if( cReply=='y' || cReply=='Y' ) rc = 0;
d685096… drh 238 blob_reset(&ans);
76bc297… andybradford 239 }
0cc4875… drh 240 return rc;
d0305b3… aku 241 }
d0305b3… aku 242
d0305b3… aku 243 /*
8dbee67… drh 244 ** This routine processes the command-line argument for push, pull,
8dbee67… drh 245 ** and sync. If a command-line argument is given, that is the URL
8dbee67… drh 246 ** of a server to sync against. If no argument is given, use the
8dbee67… drh 247 ** most recently synced URL. Remember the current URL for next time.
8dbee67… drh 248 */
27d743e… drh 249 static void process_sync_args(
27d743e… drh 250 unsigned *pConfigFlags, /* Write configuration flags here */
27d743e… drh 251 unsigned *pSyncFlags, /* Write sync flags here */
6696d4d… drh 252 int uvOnly, /* Special handling flags for UV sync */
6696d4d… drh 253 unsigned urlOmitFlags /* Omit these URL flags */
27d743e… drh 254 ){
8dbee67… drh 255 const char *zUrl = 0;
5d536c5… drh 256 const char *zHttpAuth = 0;
1570857… drh 257 unsigned configSync = 0;
6d6740d… drh 258 unsigned urlFlags = URL_REMEMBER | URL_PROMPT_PW;
bb0cedb… drh 259 int urlOptional = 0;
bb0cedb… drh 260 if( find_option("autourl",0,0)!=0 ){
bb0cedb… drh 261 urlOptional = 1;
bb0cedb… drh 262 urlFlags = 0;
bb0cedb… drh 263 }
5d536c5… drh 264 zHttpAuth = find_option("httpauth","B",1);
6d6740d… drh 265 if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER;
b3f3a89… drh 266 if( (*pSyncFlags) & SYNC_FROMPARENT ) urlFlags |= URL_USE_PARENT;
27d743e… drh 267 if( !uvOnly ){
27d743e… drh 268 if( find_option("private",0,0)!=0 ){
27d743e… drh 269 *pSyncFlags |= SYNC_PRIVATE;
27d743e… drh 270 }
27d743e… drh 271 /* The --verily option to sync, push, and pull forces extra igot cards
27d743e… drh 272 ** to be exchanged. This can overcome malfunctions in the sync protocol.
27d743e… drh 273 */
27d743e… drh 274 if( find_option("verily",0,0)!=0 ){
27d743e… drh 275 *pSyncFlags |= SYNC_RESYNC;
27d743e… drh 276 }
27d743e… drh 277 }
1570857… drh 278 if( find_option("private",0,0)!=0 ){
1570857… drh 279 *pSyncFlags |= SYNC_PRIVATE;
1570857… drh 280 }
1570857… drh 281 if( find_option("verbose","v",0)!=0 ){
1570857… drh 282 *pSyncFlags |= SYNC_VERBOSE;
8089622… drh 283 if( find_option("verbose","v",0)!=0 ){
8089622… drh 284 *pSyncFlags |= SYNC_XVERBOSE;
8089622… drh 285 }
2b8ac4d… drh 286 }
2b8ac4d… drh 287 if( find_option("no-http-compression",0,0)!=0 ){
2b8ac4d… drh 288 *pSyncFlags |= SYNC_NOHTTPCOMPRESS;
2b8ac4d… drh 289 }
6b4a04d… drh 290 if( find_option("all",0,0)!=0 ){
6b4a04d… drh 291 *pSyncFlags |= SYNC_ALLURL;
6b4a04d… drh 292 }
0a91005… drh 293
0a91005… drh 294 /* Undocumented option to cause links transitive links to other
0a91005… drh 295 ** repositories to be shared */
12d2f70… drh 296 if( ((*pSyncFlags) & SYNC_PULL)!=0
12d2f70… drh 297 && find_option("share-links",0,0)!=0
12d2f70… drh 298 ){
12d2f70… drh 299 *pSyncFlags |= SYNC_SHARE_LINKS;
12d2f70… drh 300 }
3cd412e… drh 301
505d9d4… drh 302 /* Option: --transport-command COMMAND
3cd412e… drh 303 **
3cd412e… drh 304 ** Causes COMMAND to be run with three arguments in order to talk
3cd412e… drh 305 ** to the server.
3cd412e… drh 306 **
3cd412e… drh 307 ** COMMAND URL PAYLOAD REPLY
3cd412e… drh 308 **
3cd412e… drh 309 ** URL is the server name. PAYLOAD is the name of a temporary file
3cd412e… drh 310 ** that will contain the xfer-protocol payload to send to the server.
3cd412e… drh 311 ** REPLY is a temporary filename in which COMMAND should write the
3cd412e… drh 312 ** content of the reply from the server.
505d9d4… drh 313 **
e2bdc10… danield 314 ** CMD is responsible for HTTP redirects. The following Fossil command
505d9d4… drh 315 ** can be used for CMD to achieve a working sync:
505d9d4… drh 316 **
505d9d4… drh 317 ** fossil test-httpmsg --xfer
3cd412e… drh 318 */
3cd412e… drh 319 g.zHttpCmd = find_option("transport-command",0,1);
3cd412e… drh 320
f652599… drh 321 url_proxy_options();
dbb5e2d… drh 322 clone_ssh_find_options();
27d743e… drh 323 if( !uvOnly ) db_find_and_open_repository(0, 0);
d1b88ad… drh 324 db_open_config(0, 1);
8dbee67… drh 325 if( g.argc==2 ){
1f7b409… drh 326 if( db_get_boolean("auto-shun",0) ) configSync = CONFIGSET_SHUN;
8dbee67… drh 327 }else if( g.argc==3 ){
8dbee67… drh 328 zUrl = g.argv[2];
6b4a04d… drh 329 if( (*pSyncFlags) & SYNC_ALLURL ){
6b4a04d… drh 330 fossil_fatal("cannot use both the --all option and specific URL \"%s\"",
6b4a04d… drh 331 zUrl);
6b4a04d… drh 332 }
d9ec49a… drh 333 }
d9ec49a… drh 334 if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL)
d9ec49a… drh 335 && db_get_boolean("uv-sync",0)
d9ec49a… drh 336 ){
d9ec49a… drh 337 *pSyncFlags |= SYNC_UNVERSIONED;
dbb5e2d… drh 338 }
6696d4d… drh 339 urlFlags &= ~urlOmitFlags;
dbb5e2d… drh 340 if( urlFlags & URL_REMEMBER ){
dbb5e2d… drh 341 clone_ssh_db_set_options();
932825b… drh 342 }
0aff8d8… drh 343 url_parse(zUrl, urlFlags|URL_USE_CONFIG);
5d536c5… drh 344 remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, zUrl);
5fdad9b… drh 345 if( g.url.protocol==0 ){
932825b… drh 346 if( urlOptional ) fossil_exit(0);
932825b… drh 347 usage("URL");
8dbee67… drh 348 }
8dbee67… drh 349 user_select();
676fdd0… drh 350 url_enable_proxy("via proxy: ");
1570857… drh 351 *pConfigFlags |= configSync;
949b321… drh 352 if( (*pSyncFlags & SYNC_ALLURL)==0 && zUrl==0 ){
808193e… drh 353 const char *zAutosync = db_get_for_subsystem("autosync", "sync");
808193e… drh 354 if( sqlite3_strglob("*all*", zAutosync)==0 ){
808193e… drh 355 *pSyncFlags |= SYNC_ALLURL;
808193e… drh 356 }
808193e… drh 357 }
8dbee67… drh 358 }
6b4a04d… drh 359
8dbee67… drh 360
8dbee67… drh 361 /*
dbda8d6… drh 362 ** COMMAND: pull
dbda8d6… drh 363 **
5153d61… drh 364 ** Usage: %fossil pull ?URL? ?options?
5153d61… drh 365 **
120f950… stephan 366 ** Pull all sharable changes from a remote repository into the local
120f950… stephan 367 ** repository. Sharable changes include public check-ins, edits to
5289bf4… drh 368 ** wiki pages, tickets, tech-notes, and forum posts. Add
120f950… stephan 369 ** the --private option to pull private branches. Use the
26d0c20… drh 370 ** "configuration pull" command to pull website configuration details.
26d0c20… drh 371 **
26d0c20… drh 372 ** If URL is not specified, then the URL from the most recent clone, push,
f11c863… drh 373 ** pull, remote, or sync command is used. See "fossil help clone" for
26d0c20… drh 374 ** details on the URL formats.
26d0c20… drh 375 **
26d0c20… drh 376 ** Options:
6b4a04d… drh 377 ** --all Pull from all remotes, not just the default
26d0c20… drh 378 ** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol,
26d0c20… drh 379 ** if required by the remote website
dddc58d… drh 380 ** --from-parent-project Pull content from the parent project
26d0c20… drh 381 ** --ipv4 Use only IPv4, not IPv6
2b8ac4d… drh 382 ** --no-http-compression Do not compress HTTP traffic
26d0c20… drh 383 ** --once Do not remember URL for subsequent syncs
26d0c20… drh 384 ** --private Pull private branches too
21e8aed… drh 385 ** --project-code CODE Use CODE as the project code
21e8aed… drh 386 ** --proxy PROXY Use the specified HTTP proxy
04c6e7e… mistachkin 387 ** -R|--repository REPO Local repository to pull into
26d0c20… drh 388 ** --ssl-identity FILE Local SSL credentials, if requested by remote
26d0c20… drh 389 ** --ssh-command SSH Use SSH as the "ssh" command
505d9d4… drh 390 ** --transport-command CMD Use external command CMD to move messages
505d9d4… drh 391 ** between client and server
8089622… drh 392 ** -v|--verbose Additional (debugging) output - use twice to
8089622… drh 393 ** also trace network traffic.
26d0c20… drh 394 ** --verily Exchange extra information with the remote
26d0c20… drh 395 ** to ensure no content is overlooked
26d0c20… drh 396 **
f2f419e… drh 397 ** See also: [[clone]], [[config]], [[push]], [[remote]], [[sync]]
dbda8d6… drh 398 */
dbda8d6… drh 399 void pull_cmd(void){
1570857… drh 400 unsigned configFlags = 0;
1570857… drh 401 unsigned syncFlags = SYNC_PULL;
6696d4d… drh 402 unsigned urlOmitFlags = 0;
21e8aed… drh 403 const char *zAltPCode = find_option("project-code",0,1);
dddc58d… drh 404 if( find_option("from-parent-project",0,0)!=0 ){
dddc58d… drh 405 syncFlags |= SYNC_FROMPARENT;
dddc58d… drh 406 }
6696d4d… drh 407 if( zAltPCode ) urlOmitFlags = URL_REMEMBER;
6696d4d… drh 408 process_sync_args(&configFlags, &syncFlags, 0, urlOmitFlags);
080ab8c… jan.nijtmans 409
74ac0c9… drh 410 /* We should be done with options.. */
74ac0c9… drh 411 verify_all_options();
74ac0c9… drh 412
6b4a04d… drh 413 client_sync_all_urls(syncFlags, configFlags, 0, zAltPCode);
dbda8d6… drh 414 }
dbda8d6… drh 415
dbda8d6… drh 416 /*
dbda8d6… drh 417 ** COMMAND: push
dbda8d6… drh 418 **
5153d61… drh 419 ** Usage: %fossil push ?URL? ?options?
5153d61… drh 420 **
120f950… stephan 421 ** Push all sharable changes from the local repository to a remote
120f950… stephan 422 ** repository. Sharable changes include public check-ins, edits to
5289bf4… drh 423 ** wiki pages, tickets, tech-notes, and forum posts. Use
120f950… stephan 424 ** --private to also push private branches. Use the "configuration
120f950… stephan 425 ** push" command to push website configuration details.
26d0c20… drh 426 **
26d0c20… drh 427 ** If URL is not specified, then the URL from the most recent clone, push,
f11c863… drh 428 ** pull, remote, or sync command is used. See "fossil help clone" for
26d0c20… drh 429 ** details on the URL formats.
26d0c20… drh 430 **
26d0c20… drh 431 ** Options:
6b4a04d… drh 432 ** --all Push to all remotes, not just the default
26d0c20… drh 433 ** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol,
26d0c20… drh 434 ** if required by the remote website
26d0c20… drh 435 ** --ipv4 Use only IPv4, not IPv6
2b8ac4d… drh 436 ** --no-http-compression Do not compress HTTP traffic
26d0c20… drh 437 ** --once Do not remember URL for subsequent syncs
26d0c20… drh 438 ** --proxy PROXY Use the specified HTTP proxy
3dcf69a… drh 439 ** --private Push private branches too
04c6e7e… mistachkin 440 ** -R|--repository REPO Local repository to push from
26d0c20… drh 441 ** --ssl-identity FILE Local SSL credentials, if requested by remote
26d0c20… drh 442 ** --ssh-command SSH Use SSH as the "ssh" command
505d9d4… drh 443 ** --transport-command CMD Use external command CMD to communicate with
505d9d4… drh 444 ** the server
88871c0… drh 445 ** -v|--verbose Additional (debugging) output - use twice for
88871c0… drh 446 ** network debugging
26d0c20… drh 447 ** --verily Exchange extra information with the remote
26d0c20… drh 448 ** to ensure no content is overlooked
26d0c20… drh 449 **
f2f419e… drh 450 ** See also: [[clone]], [[config]], [[pull]], [[remote]], [[sync]]
dbda8d6… drh 451 */
dbda8d6… drh 452 void push_cmd(void){
1570857… drh 453 unsigned configFlags = 0;
1570857… drh 454 unsigned syncFlags = SYNC_PUSH;
6696d4d… drh 455 process_sync_args(&configFlags, &syncFlags, 0, 0);
080ab8c… jan.nijtmans 456
74ac0c9… drh 457 /* We should be done with options.. */
74ac0c9… drh 458 verify_all_options();
74ac0c9… drh 459
21ceccd… drh 460 if( db_get_boolean("dont-push",0) ){
21ceccd… drh 461 fossil_fatal("pushing is prohibited: the 'dont-push' option is set");
21ceccd… drh 462 }
6b4a04d… drh 463 client_sync_all_urls(syncFlags, 0, 0, 0);
dbda8d6… drh 464 }
dbda8d6… drh 465
dbda8d6… drh 466
dbda8d6… drh 467 /*
dbda8d6… drh 468 ** COMMAND: sync
dbda8d6… drh 469 **
d919a33… stephan 470 ** Usage: %fossil sync ?REMOTE? ?options?
35d43fd… drh 471 **
35d43fd… drh 472 ** Synchronize all sharable changes between the local repository and a
d919a33… stephan 473 ** remote repository, with the remote provided as a URL or a
d919a33… stephan 474 ** configured remote name (see the [[remote]] command). Sharable
d919a33… stephan 475 ** changes include public check-ins and edits to wiki pages, tickets,
d919a33… stephan 476 ** forum posts, and technical notes.
35d43fd… drh 477 **
d919a33… stephan 478 ** If REMOTE is not specified, then the URL from the most recent clone, push,
f11c863… drh 479 ** pull, remote, or sync command is used. See "fossil help clone" for
26d0c20… drh 480 ** details on the URL formats.
26d0c20… drh 481 **
26d0c20… drh 482 ** Options:
6b4a04d… drh 483 ** --all Sync with all remotes, not just the default
26d0c20… drh 484 ** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol,
26d0c20… drh 485 ** if required by the remote website
26d0c20… drh 486 ** --ipv4 Use only IPv4, not IPv6
2b8ac4d… drh 487 ** --no-http-compression Do not compress HTTP traffic
26d0c20… drh 488 ** --once Do not remember URL for subsequent syncs
8fa8fe8… drh 489 ** --ping Just verify that the server is alive
26d0c20… drh 490 ** --proxy PROXY Use the specified HTTP proxy
3dcf69a… drh 491 ** --private Sync private branches too
8fa8fe8… drh 492 ** -q|--quiet Omit all output
04c6e7e… mistachkin 493 ** -R|--repository REPO Local repository to sync with
26d0c20… drh 494 ** --ssl-identity FILE Local SSL credentials, if requested by remote
26d0c20… drh 495 ** --ssh-command SSH Use SSH as the "ssh" command
505d9d4… drh 496 ** --transport-command CMD Use external command CMD to move message
505d9d4… drh 497 ** between the client and the server
c18f231… drh 498 ** -u|--unversioned Also sync unversioned content
88871c0… drh 499 ** -v|--verbose Additional (debugging) output - use twice to
88871c0… drh 500 ** get network debug info
26d0c20… drh 501 ** --verily Exchange extra information with the remote
26d0c20… drh 502 ** to ensure no content is overlooked
26d0c20… drh 503 **
c965636… drh 504 ** See also: [[clone]], [[pull]], [[push]], [[remote]]
dbda8d6… drh 505 */
dbda8d6… drh 506 void sync_cmd(void){
1570857… drh 507 unsigned configFlags = 0;
1570857… drh 508 unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
c18f231… drh 509 if( find_option("unversioned","u",0)!=0 ){
c18f231… drh 510 syncFlags |= SYNC_UNVERSIONED;
c18f231… drh 511 }
8fa8fe8… drh 512 if( find_option("ping",0,0)!=0 ){
8fa8fe8… drh 513 syncFlags = SYNC_PING;
8fa8fe8… drh 514 }
74d5ce3… florian 515 if( g.fQuiet ){
8fa8fe8… drh 516 syncFlags |= SYNC_QUIET;
8fa8fe8… drh 517 }
6696d4d… drh 518 process_sync_args(&configFlags, &syncFlags, 0, 0);
c18f231… drh 519
c18f231… drh 520 /* We should be done with options.. */
c18f231… drh 521 verify_all_options();
c18f231… drh 522
8fa8fe8… drh 523 if( (syncFlags & SYNC_PING)==0 ){
8fa8fe8… drh 524 if( db_get_boolean("dont-push",0) ) syncFlags &= ~SYNC_PUSH;
8fa8fe8… drh 525 if( (syncFlags & SYNC_PUSH)==0 ){
8fa8fe8… drh 526 fossil_warning("pull only: the 'dont-push' option is set");
8fa8fe8… drh 527 }
c18f231… drh 528 }
6b4a04d… drh 529 client_sync_all_urls(syncFlags, configFlags, 0, 0);
c18f231… drh 530 }
c18f231… drh 531
c18f231… drh 532 /*
c18f231… drh 533 ** Handle the "fossil unversioned sync" and "fossil unversioned revert"
c18f231… drh 534 ** commands.
c18f231… drh 535 */
c18f231… drh 536 void sync_unversioned(unsigned syncFlags){
c18f231… drh 537 unsigned configFlags = 0;
c18f231… drh 538 (void)find_option("uv-noop",0,0);
6696d4d… drh 539 process_sync_args(&configFlags, &syncFlags, 1, 0);
c18f231… drh 540 verify_all_options();
0cd5589… drh 541 client_sync(syncFlags, 0, 0, 0, 0);
c18f231… drh 542 }
c18f231… drh 543
c18f231… drh 544 /*
84f697e… drh 545 ** COMMAND: remote
84f697e… drh 546 ** COMMAND: remote-url*
f11c863… drh 547 **
f11c863… drh 548 ** Usage: %fossil remote ?SUBCOMMAND ...?
f11c863… drh 549 **
bbf17ae… drh 550 ** View or modify the URLs of remote repositories used for syncing.
2a3e851… mark 551 ** The "default" remote is specially named by Fossil and corresponds to
2a3e851… mark 552 ** the URL used in the most recent "sync", "push", "pull", "clone", or
2a3e851… mark 553 ** similar command. As such, the default remote can be updated by
2a3e851… mark 554 ** Fossil with each sync command. Other named remotes are persistent.
c8212fd… drh 555 **
c8212fd… drh 556 ** > fossil remote
c8212fd… drh 557 **
6d7b5c4… wyoung 558 ** With no arguments, this command shows the current default remote
6d7b5c4… wyoung 559 ** URL. If there is no default, it shows "off".
c8212fd… drh 560 **
c8212fd… drh 561 ** > fossil remote add NAME URL
c8212fd… drh 562 **
bbf17ae… drh 563 ** Add a new named URL. Afterwards, NAME can be used as a short
bbf17ae… drh 564 ** symbolic name for URL in contexts where a URL is required. The
2a3e851… mark 565 ** URL argument can be "default" or a prior symbolic name to make
2a3e851… mark 566 ** a copy of an existing URL under the new NAME. The "default"
2a3e851… mark 567 ** remote cannot be defined with this subcommand; instead,
2a3e851… mark 568 ** use 'fossil remote REF' as documented below.
bbf17ae… drh 569 **
7ea1b38… drh 570 ** > fossil remote config-data
bbf17ae… drh 571 **
bbf17ae… drh 572 ** DEBUG USE ONLY - Show the name and value of every CONFIG table
bbf17ae… drh 573 ** entry in the repository that is associated with the remote URL store.
bbf17ae… drh 574 ** Passwords are obscured in the output.
c8212fd… drh 575 **
c8212fd… drh 576 ** > fossil remote delete NAME
c8212fd… drh 577 **
bbf17ae… drh 578 ** Delete a named URL previously created by the "add" subcommand.
bbf17ae… drh 579 **
b2e2fc0… drh 580 ** > fossil remote hyperlink ?FILENAME? ?LINENUM? ?LINENUM?
b2e2fc0… drh 581 **
bc36fdc… danield 582 ** Print a URL that will access the current check-out on the remote
b2e2fc0… drh 583 ** repository. Or if the FILENAME argument is included, print the
bc36fdc… danield 584 ** URL to access that particular file within the current check-out.
b2e2fc0… drh 585 ** If one or two linenumber arguments are provided after the filename,
b2e2fc0… drh 586 ** then the URL is for the line or range of lines specified.
b2e2fc0… drh 587 **
7f3c728… jamsek 588 ** > fossil remote list|ls
c8212fd… drh 589 **
bbf17ae… drh 590 ** Show all remote repository URLs.
c8212fd… drh 591 **
c8212fd… drh 592 ** > fossil remote off
c8212fd… drh 593 **
275da70… danield 594 ** Forget the default URL. This disables autosync.
bbf17ae… drh 595 **
bbf17ae… drh 596 ** This is a convenient way to enter "airplane mode". To enter
bbf17ae… drh 597 ** airplane mode, first save the current default URL, then turn the
bbf17ae… drh 598 ** default off. Perhaps like this:
bbf17ae… drh 599 **
bbf17ae… drh 600 ** fossil remote add main default
bbf17ae… drh 601 ** fossil remote off
bbf17ae… drh 602 **
bbf17ae… drh 603 ** To exit airplane mode and turn autosync back on again:
7f2e34c… drh 604 **
bbf17ae… drh 605 ** fossil remote main
7f2e34c… drh 606 **
7f2e34c… drh 607 ** > fossil remote scrub
7f2e34c… drh 608 **
7f2e34c… drh 609 ** Forget any saved passwords for remote repositories, but continue
7f2e34c… drh 610 ** to remember the URLs themselves. You will be prompted for the
7f2e34c… drh 611 ** password the next time it is needed.
bbf17ae… drh 612 **
b2e2fc0… drh 613 ** > fossil remote ui ?FILENAME? ?LINENUM? ?LINENUM?
b2e2fc0… drh 614 **
b2e2fc0… drh 615 ** Bring up a web browser pointing at the remote repository, and
bc36fdc… danield 616 ** specifically to the page that describes the current check-out
b2e2fc0… drh 617 ** on that remote repository. Or if FILENAME and/or LINENUM arguments
b2e2fc0… drh 618 ** are provided, to the specific file and range of lines. This
b2e2fc0… drh 619 ** command is similar to "fossil remote hyperlink" except that instead
b2e2fc0… drh 620 ** of printing the URL, it passes the URL off to the web browser.
b2e2fc0… drh 621 **
292ba94… wyoung 622 ** > fossil remote REF
c8212fd… drh 623 **
6d7b5c4… wyoung 624 ** Make REF the new default URL, replacing the prior default.
6d7b5c4… wyoung 625 ** REF may be a URL or a NAME from a prior "add".
c18f231… drh 626 */
c18f231… drh 627 void remote_url_cmd(void){
f11c863… drh 628 char *zUrl, *zArg;
f11c863… drh 629 int nArg;
41ba6ea… drh 630 int showPw;
c18f231… drh 631 db_find_and_open_repository(0, 0);
41ba6ea… drh 632 showPw = find_option("show-passwords",0,0)!=0;
c18f231… drh 633
c18f231… drh 634 /* We should be done with options.. */
c18f231… drh 635 verify_all_options();
6330e86… drh 636
6330e86… drh 637 /* 2021-10-25: A note about data structures.
6330e86… drh 638 **
6330e86… drh 639 ** The remote URLs are stored in the CONFIG table. The URL is stored
6330e86… drh 640 ** separately from the password. The password is obscured using the
6330e86… drh 641 ** obscure() function.
6330e86… drh 642 **
6330e86… drh 643 ** Originally, Fossil only preserved a single remote URL. That URL
6330e86… drh 644 ** is stored in "last-sync-url" and the password in "last-sync-pw". The
6330e86… drh 645 ** ability to have multiple remotes was added later so these names
6330e86… drh 646 ** were retained for backwards compatibility. The other remotes are
6330e86… drh 647 ** stored in "sync-url:NAME" and "sync-pw:NAME" where NAME is the name
6330e86… drh 648 ** of the remote.
6330e86… drh 649 **
6330e86… drh 650 ** The last-sync-url is called "default" for the display list.
6330e86… drh 651 **
6330e86… drh 652 ** The last-sync-url might be duplicated into one of the sync-url:NAME
6330e86… drh 653 ** entries. Thus, when doing a "fossil sync --all" or an autosync with
6330e86… drh 654 ** autosync=all, each sync-url:NAME entry is checked to see if it is the
6330e86… drh 655 ** same as last-sync-url and if it is then that entry is skipped.
275da70… danield 656 */
f11c863… drh 657
f11c863… drh 658 if( g.argc==2 ){
f11c863… drh 659 /* "fossil remote" with no arguments: Show the last sync URL. */
f11c863… drh 660 zUrl = db_get("last-sync-url", 0);
f11c863… drh 661 if( zUrl==0 ){
f11c863… drh 662 fossil_print("off\n");
f11c863… drh 663 }else{
f11c863… drh 664 url_parse(zUrl, 0);
f11c863… drh 665 fossil_print("%s\n", g.url.canonical);
f11c863… drh 666 }
f11c863… drh 667 return;
f11c863… drh 668 }
f11c863… drh 669 zArg = g.argv[2];
f11c863… drh 670 nArg = (int)strlen(zArg);
f11c863… drh 671 if( strcmp(zArg,"off")==0 ){
f11c863… drh 672 /* fossil remote off
f11c863… drh 673 ** Forget the last-sync-URL and its password
f11c863… drh 674 */
f11c863… drh 675 if( g.argc!=3 ) usage("off");
f11c863… drh 676 remote_delete_default:
f741baa… drh 677 db_unprotect(PROTECT_CONFIG);
f11c863… drh 678 db_multi_exec(
f11c863… drh 679 "DELETE FROM config WHERE name GLOB 'last-sync-*';"
f11c863… drh 680 );
f741baa… drh 681 db_protect_pop();
f11c863… drh 682 return;
f11c863… drh 683 }
f11c863… drh 684 if( strncmp(zArg, "list", nArg)==0 || strcmp(zArg,"ls")==0 ){
f11c863… drh 685 Stmt q;
f11c863… drh 686 if( g.argc!=3 ) usage("list");
f11c863… drh 687 db_prepare(&q,
f11c863… drh 688 "SELECT 'default', value FROM config WHERE name='last-sync-url'"
f11c863… drh 689 " UNION ALL "
f11c863… drh 690 "SELECT substr(name,10), value FROM config"
f11c863… drh 691 " WHERE name GLOB 'sync-url:*'"
f11c863… drh 692 " ORDER BY 1"
f11c863… drh 693 );
f11c863… drh 694 while( db_step(&q)==SQLITE_ROW ){
f11c863… drh 695 fossil_print("%-18s %s\n", db_column_text(&q,0), db_column_text(&q,1));
f11c863… drh 696 }
f11c863… drh 697 db_finalize(&q);
f11c863… drh 698 return;
f11c863… drh 699 }
f11c863… drh 700 if( strcmp(zArg, "add")==0 ){
f11c863… drh 701 char *zName;
f11c863… drh 702 char *zUrl;
f11c863… drh 703 UrlData x;
f11c863… drh 704 if( g.argc!=5 ) usage("add NAME URL");
f11c863… drh 705 memset(&x, 0, sizeof(x));
f11c863… drh 706 zName = g.argv[3];
f11c863… drh 707 zUrl = g.argv[4];
2a3e851… mark 708 if( strcmp(zName,"default")==0 ){
2a3e851… mark 709 fossil_fatal("update the \"default\" remote-url with 'fossil remote REF'"
2a3e851… mark 710 "\nsee 'fossil help remote' for complete usage information");
2a3e851… mark 711 }
f11c863… drh 712 db_begin_write();
ce1a1fd… drh 713 if( fossil_strcmp(zUrl,"default")==0 ){
ce1a1fd… drh 714 x.canonical = db_get("last-sync-url",0);
ce1a1fd… drh 715 x.passwd = unobscure(db_get("last-sync-pw",0));
ce1a1fd… drh 716 }else{
c301e29… drh 717 url_parse_local(zUrl, URL_PROMPT_PW|URL_USE_CONFIG, &x);
ce1a1fd… drh 718 }
f741baa… drh 719 db_unprotect(PROTECT_CONFIG);
f11c863… drh 720 db_multi_exec(
f11c863… drh 721 "REPLACE INTO config(name, value, mtime)"
f11c863… drh 722 " VALUES('sync-url:%q',%Q,now())",
f11c863… drh 723 zName, x.canonical
f11c863… drh 724 );
f11c863… drh 725 db_multi_exec(
f11c863… drh 726 "REPLACE INTO config(name, value, mtime)"
f11c863… drh 727 " VALUES('sync-pw:%q',obscure(%Q),now())",
f11c863… drh 728 zName, x.passwd
f11c863… drh 729 );
f741baa… drh 730 db_protect_pop();
f11c863… drh 731 db_commit_transaction();
f11c863… drh 732 return;
f11c863… drh 733 }
f11c863… drh 734 if( strncmp(zArg, "delete", nArg)==0 ){
f11c863… drh 735 char *zName;
f11c863… drh 736 if( g.argc!=4 ) usage("delete NAME");
f11c863… drh 737 zName = g.argv[3];
59645b6… drh 738 if( strcmp(zName,"default")==0 ) goto remote_delete_default;
f11c863… drh 739 db_begin_write();
f741baa… drh 740 db_unprotect(PROTECT_CONFIG);
f11c863… drh 741 db_multi_exec("DELETE FROM config WHERE name glob 'sync-url:%q'", zName);
f11c863… drh 742 db_multi_exec("DELETE FROM config WHERE name glob 'sync-pw:%q'", zName);
f741baa… drh 743 db_protect_pop();
f741baa… drh 744 db_commit_transaction();
f741baa… drh 745 return;
f741baa… drh 746 }
b2e2fc0… drh 747 if( strncmp(zArg, "hyperlink", nArg)==0
b2e2fc0… drh 748 || (nArg==2 && strcmp(zArg, "ui")==0)
b2e2fc0… drh 749 ){
b2e2fc0… drh 750 char *zBase;
b2e2fc0… drh 751 char *zUuid;
b2e2fc0… drh 752 Blob fname;
b2e2fc0… drh 753 Blob url;
b2e2fc0… drh 754 char *zSubCmd = g.argv[2][0]=='u' ? "ui" : "hyperlink";
b2e2fc0… drh 755 if( !db_table_exists("localdb","vvar") ){
b2e2fc0… drh 756 fossil_fatal("the \"remote %s\" command only works from "
b2e2fc0… drh 757 "within an open check-out", zSubCmd);
b2e2fc0… drh 758 }
b2e2fc0… drh 759 zUrl = db_get("last-sync-url", 0);
b2e2fc0… drh 760 if( zUrl==0 ){
b2e2fc0… drh 761 zUrl = "http://localhost:8080/";
b2e2fc0… drh 762 }
b2e2fc0… drh 763 url_parse(zUrl, 0);
b2e2fc0… drh 764 if( g.url.isFile ){
b2e2fc0… drh 765 url_parse("http://localhost:8080/", 0);
b2e2fc0… drh 766 }
b2e2fc0… drh 767 zBase = url_nouser(&g.url);
b2e2fc0… drh 768 blob_init(&url, 0, 0);
b2e2fc0… drh 769 if( g.argc==3 ){
76bc66a… drh 770 blob_appendf(&url, "%s/info/%!S",
b2e2fc0… drh 771 zBase,
b2e2fc0… drh 772 db_text("???",
b2e2fc0… drh 773 "SELECT uuid FROM blob, vvar"
b2e2fc0… drh 774 " WHERE blob.rid=0+vvar.value"
b2e2fc0… drh 775 " AND vvar.name='checkout';"
b2e2fc0… drh 776 ));
b2e2fc0… drh 777 }else{
b2e2fc0… drh 778 blob_init(&fname, 0, 0);
b2e2fc0… drh 779 file_tree_name(g.argv[3], &fname, 0, 1);
b2e2fc0… drh 780 zUuid = db_text(0,
b2e2fc0… drh 781 "SELECT uuid FROM files_of_checkin"
b2e2fc0… drh 782 " WHERE checkinID=(SELECT value FROM vvar WHERE name='checkout')"
b2e2fc0… drh 783 " AND filename=%Q",
b2e2fc0… drh 784 blob_str(&fname)
b2e2fc0… drh 785 );
b2e2fc0… drh 786 if( zUuid==0 ){
b2e2fc0… drh 787 fossil_fatal("not a managed file: \"%s\"", g.argv[3]);
b2e2fc0… drh 788 }
b2e2fc0… drh 789 blob_appendf(&url, "%s/info/%S",zBase,zUuid);
b2e2fc0… drh 790 if( g.argc>4 ){
b2e2fc0… drh 791 int ln1 = atoi(g.argv[4]);
b2e2fc0… drh 792 if( ln1<=0 || sqlite3_strglob("*[^0-9]*",g.argv[4])==0 ){
b2e2fc0… drh 793 fossil_fatal("\"%s\" is not a valid line number", g.argv[4]);
b2e2fc0… drh 794 }
b2e2fc0… drh 795 if( g.argc>5 ){
b2e2fc0… drh 796 int ln2 = atoi(g.argv[5]);
b2e2fc0… drh 797 if( ln2==0 || sqlite3_strglob("*[^0-9]*",g.argv[5])==0 ){
b2e2fc0… drh 798 fossil_fatal("\"%s\" is not a valid line number", g.argv[5]);
b2e2fc0… drh 799 }
b2e2fc0… drh 800 if( ln2<=ln1 ){
b2e2fc0… drh 801 fossil_fatal("second line number should be greater than the first");
b2e2fc0… drh 802 }
b2e2fc0… drh 803 blob_appendf(&url,"?ln=%d,%d", ln1, ln2);
b2e2fc0… drh 804 }else{
b2e2fc0… drh 805 blob_appendf(&url,"?ln=%d", ln1);
b2e2fc0… drh 806 }
b2e2fc0… drh 807 }
b2e2fc0… drh 808 if( g.argc>6 ){
b2e2fc0… drh 809 usage(mprintf("%s ?FILENAME? ?LINENUMBER? ?LINENUMBER?", zSubCmd));
b2e2fc0… drh 810 }
b2e2fc0… drh 811 }
b2e2fc0… drh 812 if( g.argv[2][0]=='u' ){
b2e2fc0… drh 813 char *zCmd;
b2e2fc0… drh 814 zCmd = mprintf("%s %!$ &", fossil_web_browser(), blob_str(&url));
b2e2fc0… drh 815 fossil_system(zCmd);
b2e2fc0… drh 816 }else{
b2e2fc0… drh 817 fossil_print("%s\n", blob_str(&url));
b2e2fc0… drh 818 }
b2e2fc0… drh 819 return;
b2e2fc0… drh 820 }
7f2e34c… drh 821 if( strncmp(zArg, "scrub", nArg)==0 ){
7f2e34c… drh 822 if( g.argc!=3 ) usage("scrub");
7f2e34c… drh 823 db_begin_write();
7f2e34c… drh 824 db_unprotect(PROTECT_CONFIG);
7f2e34c… drh 825 db_multi_exec("DELETE FROM config WHERE name glob 'sync-pw:*'");
7f2e34c… drh 826 db_multi_exec("DELETE FROM config WHERE name = 'last-sync-pw'");
7f2e34c… drh 827 db_protect_pop();
7f2e34c… drh 828 db_commit_transaction();
7f2e34c… drh 829 return;
7f2e34c… drh 830 }
bd7f272… danield 831 if( strncmp(zArg, "config-data", nArg)==0 ){
41ba6ea… drh 832 /* Undocumented command: "fossil remote config-data [-show-passwords]"
bd7f272… danield 833 **
bd7f272… danield 834 ** Show the CONFIG table entries that relate to remembering remote URLs
bd7f272… danield 835 */
bd7f272… danield 836 Stmt q;
bd7f272… danield 837 int n;
41ba6ea… drh 838 sqlite3_create_function(g.db, "unobscure", 1, SQLITE_UTF8, &g.db,
41ba6ea… drh 839 db_obscure, 0, 0);
bd7f272… danield 840 n = db_int(13,
bd7f272… danield 841 "SELECT max(length(name))"
bd7f272… danield 842 " FROM config"
6d0083a… drh 843 " WHERE name GLOB 'sync-*:*'"
6d0083a… drh 844 " OR name GLOB 'last-sync-*'"
6d0083a… drh 845 " OR name GLOB 'parent-project-*'"
bd7f272… danield 846 );
bd7f272… danield 847 db_prepare(&q,
41ba6ea… drh 848 "SELECT name,"
41ba6ea… drh 849 " CASE WHEN name NOT LIKE '%%sync-pw%%' AND name<>'parent-project-pw'"
41ba6ea… drh 850 " THEN value"
41ba6ea… drh 851 " WHEN %d THEN unobscure(value)"
41ba6ea… drh 852 " ELSE printf('%%.*c',length(value)/2-1,'*') END"
41ba6ea… drh 853 " FROM config"
41ba6ea… drh 854 " WHERE name GLOB 'sync-*:*'"
41ba6ea… drh 855 " OR name GLOB 'last-sync-*'"
41ba6ea… drh 856 " OR name GLOB 'parent-project-*'"
41ba6ea… drh 857 " ORDER BY name LIKE '%%sync-pw%%' OR name='parent-project-pw', name",
41ba6ea… drh 858 showPw
bd7f272… danield 859 );
bd7f272… danield 860 while( db_step(&q)==SQLITE_ROW ){
bd7f272… danield 861 fossil_print("%-*s %s\n",
bd7f272… danield 862 n, db_column_text(&q,0),
bd7f272… danield 863 db_column_text(&q,1)
bd7f272… danield 864 );
bd7f272… danield 865 }
bd7f272… danield 866 db_finalize(&q);
bd7f272… danield 867 return;
bd7f272… danield 868 }
f11c863… drh 869 if( sqlite3_strlike("http://%",zArg,0)==0
f11c863… drh 870 || sqlite3_strlike("https://%",zArg,0)==0
f11c863… drh 871 || sqlite3_strlike("ssh:%",zArg,0)==0
f11c863… drh 872 || sqlite3_strlike("file:%",zArg,0)==0
f11c863… drh 873 || db_exists("SELECT 1 FROM config WHERE name='sync-url:%q'",zArg)
f11c863… drh 874 ){
c18f231… drh 875 db_unset("last-sync-url", 0);
c18f231… drh 876 db_unset("last-sync-pw", 0);
bcb09d6… drh 877 url_parse(g.argv[2], URL_REMEMBER|URL_PROMPT_PW|
bcb09d6… drh 878 URL_USE_CONFIG|URL_ASK_REMEMBER_PW);
f11c863… drh 879 url_remember();
c18f231… drh 880 return;
aadbe01… drh 881 }
f11c863… drh 882 fossil_fatal("unknown command \"%s\" - should be a URL or one of: "
b2e2fc0… drh 883 "add delete hyperlink list off scrub", zArg);
aadbe01… drh 884 }
aadbe01… drh 885
aadbe01… drh 886 /*
aadbe01… drh 887 ** COMMAND: backup*
aadbe01… drh 888 **
aadbe01… drh 889 ** Usage: %fossil backup ?OPTIONS? FILE|DIRECTORY
aadbe01… drh 890 **
aadbe01… drh 891 ** Make a backup of the repository into the named file or into the named
aadbe01… drh 892 ** directory. This backup is guaranteed to be consistent even if there are
80ca317… andygoth 893 ** concurrent changes taking place on the repository. In other words, it
aadbe01… drh 894 ** is safe to run "fossil backup" on a repository that is in active use.
aadbe01… drh 895 **
aadbe01… drh 896 ** Only the main repository database is backed up by this command. The
bc36fdc… danield 897 ** open check-out file (if any) is not saved. Nor is the global configuration
aadbe01… drh 898 ** database.
aadbe01… drh 899 **
aadbe01… drh 900 ** Options:
80ca317… andygoth 901 ** --overwrite OK to overwrite an existing file
aadbe01… drh 902 ** -R NAME Filename of the repository to backup
aadbe01… drh 903 */
aadbe01… drh 904 void backup_cmd(void){
aadbe01… drh 905 char *zDest;
aadbe01… drh 906 int bOverwrite = 0;
aadbe01… drh 907 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
aadbe01… drh 908 bOverwrite = find_option("overwrite",0,0)!=0;
aadbe01… drh 909 verify_all_options();
aadbe01… drh 910 if( g.argc!=3 ){
aadbe01… drh 911 usage("FILE|DIRECTORY");
aadbe01… drh 912 }
aadbe01… drh 913 zDest = g.argv[2];
aadbe01… drh 914 if( file_isdir(zDest, ExtFILE)==1 ){
aadbe01… drh 915 zDest = mprintf("%s/%s", zDest, file_tail(g.zRepositoryName));
aadbe01… drh 916 }
aadbe01… drh 917 if( file_isfile(zDest, ExtFILE) ){
aadbe01… drh 918 if( bOverwrite ){
aadbe01… drh 919 if( file_delete(zDest) ){
aadbe01… drh 920 fossil_fatal("unable to delete old copy of \"%s\"", zDest);
aadbe01… drh 921 }
aadbe01… drh 922 }else{
aadbe01… drh 923 fossil_fatal("backup \"%s\" already exists", zDest);
aadbe01… drh 924 }
c18f231… drh 925 }
f741baa… drh 926 db_unprotect(PROTECT_ALL);
aadbe01… drh 927 db_multi_exec("VACUUM repository INTO %Q", zDest);
dbda8d6… drh 928 }

Keyboard Shortcuts

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