Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | The --share-links option on "fossil sync" and similar causes the server to reply with "pragma link" lines that identify other repositories with which the server has interacted within the past month. Those links are recorded in "link:URL" entries of the CONFIG table on the client. |
|---|---|
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
12d2f70bdff55411e8a0df1a62d50215 |
| User & Date: | drh 2021-12-21 19:50:31.088 |
Context
|
2021-12-21
| ||
| 20:20 | Add the "Links from other repositories" section on the /urllist page. check-in: 6916a058ab user: drh tags: trunk | |
| 19:50 | The --share-links option on "fossil sync" and similar causes the server to reply with "pragma link" lines that identify other repositories with which the server has interacted within the past month. Those links are recorded in "link:URL" entries of the CONFIG table on the client. check-in: 12d2f70bdf user: drh tags: trunk | |
| 18:22 | For "fossil git export", add the comment line at the end of automatically generated "manifest" files so that they do not appear to be valid Fossil artifacts. check-in: 4ff45df429 user: drh tags: trunk | |
Changes
Changes to src/sync.c.
| ︙ | ︙ | |||
230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
}
if( find_option("no-http-compression",0,0)!=0 ){
*pSyncFlags |= SYNC_NOHTTPCOMPRESS;
}
if( find_option("all",0,0)!=0 ){
*pSyncFlags |= SYNC_ALLURL;
}
url_proxy_options();
clone_ssh_find_options();
if( !uvOnly ) db_find_and_open_repository(0, 0);
db_open_config(0, 1);
if( g.argc==2 ){
if( db_get_boolean("auto-shun",0) ) configSync = CONFIGSET_SHUN;
}else if( g.argc==3 ){
| > > > > > | 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
}
if( find_option("no-http-compression",0,0)!=0 ){
*pSyncFlags |= SYNC_NOHTTPCOMPRESS;
}
if( find_option("all",0,0)!=0 ){
*pSyncFlags |= SYNC_ALLURL;
}
if( ((*pSyncFlags) & SYNC_PULL)!=0
&& find_option("share-links",0,0)!=0
){
*pSyncFlags |= SYNC_SHARE_LINKS;
}
url_proxy_options();
clone_ssh_find_options();
if( !uvOnly ) db_find_and_open_repository(0, 0);
db_open_config(0, 1);
if( g.argc==2 ){
if( db_get_boolean("auto-shun",0) ) configSync = CONFIGSET_SHUN;
}else if( g.argc==3 ){
|
| ︙ | ︙ | |||
292 293 294 295 296 297 298 299 300 301 302 303 304 305 | ** --ipv4 Use only IPv4, not IPv6 ** --no-http-compression Do not compress HTTP traffic ** --once Do not remember URL for subsequent syncs ** --private Pull private branches too ** --project-code CODE Use CODE as the project code ** --proxy PROXY Use the specified HTTP proxy ** -R|--repository REPO Local repository to pull into ** --ssl-identity FILE Local SSL credentials, if requested by remote ** --ssh-command SSH Use SSH as the "ssh" command ** -v|--verbose Additional (debugging) output ** --verily Exchange extra information with the remote ** to ensure no content is overlooked ** ** See also: [[clone]], [[config]], [[push]], [[remote]], [[sync]] | > | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | ** --ipv4 Use only IPv4, not IPv6 ** --no-http-compression Do not compress HTTP traffic ** --once Do not remember URL for subsequent syncs ** --private Pull private branches too ** --project-code CODE Use CODE as the project code ** --proxy PROXY Use the specified HTTP proxy ** -R|--repository REPO Local repository to pull into ** --share-links Share links to mirror repos ** --ssl-identity FILE Local SSL credentials, if requested by remote ** --ssh-command SSH Use SSH as the "ssh" command ** -v|--verbose Additional (debugging) output ** --verily Exchange extra information with the remote ** to ensure no content is overlooked ** ** See also: [[clone]], [[config]], [[push]], [[remote]], [[sync]] |
| ︙ | ︙ | |||
390 391 392 393 394 395 396 397 398 399 400 401 402 403 | ** if required by the remote website ** --ipv4 Use only IPv4, not IPv6 ** --no-http-compression Do not compress HTTP traffic ** --once Do not remember URL for subsequent syncs ** --proxy PROXY Use the specified HTTP proxy ** --private Sync private branches too ** -R|--repository REPO Local repository to sync with ** --ssl-identity FILE Local SSL credentials, if requested by remote ** --ssh-command SSH Use SSH as the "ssh" command ** -u|--unversioned Also sync unversioned content ** -v|--verbose Additional (debugging) output ** --verily Exchange extra information with the remote ** to ensure no content is overlooked ** | > | 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 | ** if required by the remote website ** --ipv4 Use only IPv4, not IPv6 ** --no-http-compression Do not compress HTTP traffic ** --once Do not remember URL for subsequent syncs ** --proxy PROXY Use the specified HTTP proxy ** --private Sync private branches too ** -R|--repository REPO Local repository to sync with ** --share-links Share links to mirror repos ** --ssl-identity FILE Local SSL credentials, if requested by remote ** --ssh-command SSH Use SSH as the "ssh" command ** -u|--unversioned Also sync unversioned content ** -v|--verbose Additional (debugging) output ** --verily Exchange extra information with the remote ** to ensure no content is overlooked ** |
| ︙ | ︙ |
Changes to src/xfer.c.
| ︙ | ︙ | |||
1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 |
int rc;
const char *zScript = 0;
char *zUuidList = 0;
int nUuidList = 0;
char **pzUuidList = 0;
int *pnUuidList = 0;
int uvCatalogSent = 0;
if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
fossil_redirect_home();
}
g.zLogin = "anonymous";
login_set_anon_nobody_capabilities();
login_check_credentials();
| > | 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 |
int rc;
const char *zScript = 0;
char *zUuidList = 0;
int nUuidList = 0;
char **pzUuidList = 0;
int *pnUuidList = 0;
int uvCatalogSent = 0;
int bSendLinks = 0;
if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
fossil_redirect_home();
}
g.zLogin = "anonymous";
login_set_anon_nobody_capabilities();
login_check_credentials();
|
| ︙ | ︙ | |||
1597 1598 1599 1600 1601 1602 1603 |
if( blob_eq(&xfer.aToken[1], "send-private") ){
login_check_credentials();
if( !g.perm.Private ){
server_private_xfer_not_authorized();
}else{
xfer.syncPrivate = 1;
}
| | | | | 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 |
if( blob_eq(&xfer.aToken[1], "send-private") ){
login_check_credentials();
if( !g.perm.Private ){
server_private_xfer_not_authorized();
}else{
xfer.syncPrivate = 1;
}
}else
/* pragma send-catalog
**
** The client wants to see igot cards for all known artifacts.
** This is used as part of "sync --verily" to help ensure that
** no artifacts have been missed on prior syncs.
*/
if( blob_eq(&xfer.aToken[1], "send-catalog") ){
xfer.resync = 0x7fffffff;
}else
/* pragma client-version VERSION ?DATE? ?TIME?
**
** The client announces to the server what version of Fossil it
** is running. The DATE and TIME are a pure numeric ISO8601 time
** for the specific check-in of the client.
*/
if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "client-version") ){
xfer.remoteVersion = atoi(blob_str(&xfer.aToken[2]));
if( xfer.nToken>=5 ){
xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
@ pragma server-version %d(RELEASE_VERSION_NUMBER) \
@ %d(MANIFEST_NUMERIC_DATE) %d(MANIFEST_NUMERIC_TIME)
}
}else
/* pragma uv-hash HASH
**
** The client wants to make sure that unversioned files are all synced.
** If the HASH does not match, send a complete catalog of
** "uvigot" cards.
*/
|
| ︙ | ︙ | |||
1646 1647 1648 1649 1650 1651 1652 |
@ pragma uv-push-ok
}else if( g.perm.Read ){
@ pragma uv-pull-only
}
send_unversioned_catalog(&xfer);
}
uvCatalogSent = 1;
| | | 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 |
@ pragma uv-push-ok
}else if( g.perm.Read ){
@ pragma uv-pull-only
}
send_unversioned_catalog(&xfer);
}
uvCatalogSent = 1;
}else
/* pragma ci-lock CHECKIN-HASH CLIENT-ID
**
** The client wants to make non-branch commit against the check-in
** identified by CHECKIN-HASH. The server will remember this and
** subsequent ci-lock requests from different clients will generate
** a ci-lock-fail pragma in the reply.
|
| ︙ | ︙ | |||
1706 1707 1708 1709 1710 1711 1712 |
blob_str(&xfer.aToken[3])
);
db_protect_pop();
}
if( db_get_boolean("forbid-delta-manifests",0) ){
@ pragma avoid-delta-manifests
}
| | | > > > > > > > > > | 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 |
blob_str(&xfer.aToken[3])
);
db_protect_pop();
}
if( db_get_boolean("forbid-delta-manifests",0) ){
@ pragma avoid-delta-manifests
}
}else
/* pragma ci-unlock CLIENT-ID
**
** Remove any locks previously held by CLIENT-ID. Clients send this
** pragma with their own ID whenever they know that they no longer
** have any commits pending.
*/
if( blob_eq(&xfer.aToken[1], "ci-unlock")
&& xfer.nToken==3
&& blob_is_hname(&xfer.aToken[2])
){
db_unprotect(PROTECT_CONFIG);
db_multi_exec(
"DELETE FROM config"
" WHERE name GLOB 'ci-lock-*'"
" AND json_extract(value,'$.clientid')=%Q",
blob_str(&xfer.aToken[2])
);
db_protect_pop();
}else
/* pragma client-url URL
**
** This pragma is an informational notification to the server that
** their relationship could, in theory, be inverted by having the
** server call the client at URL.
*/
if( blob_eq(&xfer.aToken[1], "client-url")
&& xfer.nToken==3
&& g.perm.Write
){
xfer_syncwith(blob_str(&xfer.aToken[2]), 1);
}else
/* pragma req-links
**
** The client sends this message to the server to ask the server
** to tell it about alternative repositories in the reply.
*/
if( blob_eq(&xfer.aToken[1], "req-links") ){
bSendLinks = 1;
}
}else
/* Unknown message
*/
{
|
| ︙ | ︙ | |||
1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 |
create_cluster();
send_unclustered(&xfer);
if( xfer.syncPrivate ) send_private(&xfer);
}
hook_expecting_more_artifacts(xfer.nGimmeSent?60:0);
db_multi_exec("DROP TABLE onremote; DROP TABLE unk;");
manifest_crosslink_end(MC_PERMIT_HOOKS);
/* Send the server timestamp last, in case prior processing happened
** to use up a significant fraction of our time window.
*/
zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
@ # timestamp %s(zNow)
free(zNow);
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 |
create_cluster();
send_unclustered(&xfer);
if( xfer.syncPrivate ) send_private(&xfer);
}
hook_expecting_more_artifacts(xfer.nGimmeSent?60:0);
db_multi_exec("DROP TABLE onremote; DROP TABLE unk;");
manifest_crosslink_end(MC_PERMIT_HOOKS);
/* Send URLs for alternative repositories for the same project,
** if requested by the client. */
if( bSendLinks && g.zBaseURL ){
Stmt q;
db_prepare(&q,
"WITH remote(mtime, url, arg) AS (\n"
" SELECT mtime, substr(name,10), '{}' FROM config\n"
" WHERE name GLOB 'syncwith:http*'\n"
" UNION ALL\n"
" SELECT mtime, substr(name,10), '{}' FROM config\n"
" WHERE name GLOB 'syncfrom:http*'\n"
" UNION ALL\n"
" SELECT mtime, substr(name,9), '{\"type\":\"git\"}' FROM config\n"
" WHERE name GLOB 'gitpush:*'\n"
")\n"
"SELECT url, json_insert(arg,'$.src',%Q), max(mtime)\n"
" FROM remote WHERE mtime>unixepoch('now','-1 month')\n"
" GROUP BY url;",
g.zBaseURL
);
while( db_step(&q)==SQLITE_ROW ){
UrlData x;
const char *zUrl = db_column_text(&q, 0);
const char *zArg = db_column_text(&q, 1);
i64 iMtime = db_column_int64(&q, 2);
memset(&x, 0, sizeof(x));
url_parse_local(zUrl, URL_OMIT_USER, &x);
if( x.name!=0 && sqlite3_strlike("%localhost%", x.name, 0)!=0 ){
@ pragma link %F(x.canonical) %F(zArg) %lld(iMtime)
}
url_unparse(&x);
}
db_finalize(&q);
}
/* Send the server timestamp last, in case prior processing happened
** to use up a significant fraction of our time window.
*/
zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
@ # timestamp %s(zNow)
free(zNow);
|
| ︙ | ︙ | |||
1840 1841 1842 1843 1844 1845 1846 | static const char zBriefFormat[] = "Round-trips: %d Artifacts sent: %d received: %d\r"; #if INTERFACE /* ** Flag options for controlling client_sync() */ | | | | | | | | | | | | | | | | > | 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 |
static const char zBriefFormat[] =
"Round-trips: %d Artifacts sent: %d received: %d\r";
#if INTERFACE
/*
** Flag options for controlling client_sync()
*/
#define SYNC_PUSH 0x00001 /* push content client to server */
#define SYNC_PULL 0x00002 /* pull content server to client */
#define SYNC_CLONE 0x00004 /* clone the repository */
#define SYNC_PRIVATE 0x00008 /* Also transfer private content */
#define SYNC_VERBOSE 0x00010 /* Extra diagnostics */
#define SYNC_RESYNC 0x00020 /* --verily */
#define SYNC_FROMPARENT 0x00040 /* Pull from the parent project */
#define SYNC_UNVERSIONED 0x00100 /* Sync unversioned content */
#define SYNC_UV_REVERT 0x00200 /* Copy server unversioned to client */
#define SYNC_UV_TRACE 0x00400 /* Describe UV activities */
#define SYNC_UV_DRYRUN 0x00800 /* Do not actually exchange files */
#define SYNC_IFABLE 0x01000 /* Inability to sync is not fatal */
#define SYNC_CKIN_LOCK 0x02000 /* Lock the current check-in */
#define SYNC_NOHTTPCOMPRESS 0x04000 /* Do not compression HTTP messages */
#define SYNC_ALLURL 0x08000 /* The --all flag - sync to all URLs */
#define SYNC_SHARE_LINKS 0x10000 /* Request alternate repo links */
#endif
/*
** Floating-point absolute value
*/
static double fossil_fabs(double x){
return x>0.0 ? x : -x;
|
| ︙ | ︙ | |||
2050 2051 2052 2053 2054 2055 2056 |
if( zAltPCode==0 ){
const char *zSelfUrl = public_url();
if( zSelfUrl ){
blob_appendf(&send, "pragma client-url %s\n", zSelfUrl);
}
}
| | | | | 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 |
if( zAltPCode==0 ){
const char *zSelfUrl = public_url();
if( zSelfUrl ){
blob_appendf(&send, "pragma client-url %s\n", zSelfUrl);
}
}
/* Request URLs of alternative repositories
*/
if( zAltPCode==0 && (syncFlags & SYNC_SHARE_LINKS)!=0 ){
blob_appendf(&send, "pragma req-links\n");
}
while( go ){
int newPhantom = 0;
char *zRandomness;
db_begin_transaction();
db_record_repository_filename(0);
|
| ︙ | ︙ | |||
2588 2589 2590 2591 2592 2593 2594 |
**
** If the server is unwill to accept new unversioned content (because
** this client lacks the necessary permissions) then it sends a
** "uv-pull-only" pragma so that the client will know not to waste
** bandwidth trying to upload unversioned content. If the server
** does accept new unversioned content, it sends "uv-push-ok".
*/
| | | 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 |
**
** If the server is unwill to accept new unversioned content (because
** this client lacks the necessary permissions) then it sends a
** "uv-pull-only" pragma so that the client will know not to waste
** bandwidth trying to upload unversioned content. If the server
** does accept new unversioned content, it sends "uv-push-ok".
*/
else if( syncFlags & SYNC_UNVERSIONED ){
if( blob_eq(&xfer.aToken[1], "uv-pull-only") ){
uvPullOnly = 1;
if( syncFlags & SYNC_UV_REVERT ) uvDoPush = 1;
}else if( blob_eq(&xfer.aToken[1], "uv-push-ok") ){
uvDoPush = 1;
}
}
|
| ︙ | ︙ | |||
2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 |
**
** Discourage the use of delta manifests. The remote side sends
** this pragma when its forbid-delta-manifests setting is true.
*/
else if( blob_eq(&xfer.aToken[1], "avoid-delta-manifests") ){
g.bAvoidDeltaManifests = 1;
}
}else
/* error MESSAGE
**
** The server is reporting an error. The client will abandon
** the sync session.
**
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 |
**
** Discourage the use of delta manifests. The remote side sends
** this pragma when its forbid-delta-manifests setting is true.
*/
else if( blob_eq(&xfer.aToken[1], "avoid-delta-manifests") ){
g.bAvoidDeltaManifests = 1;
}
/* pragma link URL ARG MTIME
**
** The server has sent the URL for a link to another repository.
** Record this as a link:URL entry in the config table.
*/
else if( blob_eq(&xfer.aToken[1], "link")
&& xfer.nToken==5
&& (syncFlags & SYNC_SHARE_LINKS)!=0
){
UrlData x;
char *zUrl = blob_str(&xfer.aToken[2]);
char *zArg = blob_str(&xfer.aToken[3]);
i64 iTime = strtoll(blob_str(&xfer.aToken[4]),0,0);
memset(&x, 0, sizeof(x));
defossilize(zUrl);
defossilize(zArg);
url_parse_local(zUrl, URL_OMIT_USER, &x);
if( x.protocol
&& strncmp(x.protocol,"http",4)==0
&& iTime>0
){
db_unprotect(PROTECT_CONFIG);
db_multi_exec(
"INSERT INTO config(name,value,mtime)\n"
" VALUES('link:%q',%Q,%lld)\n"
" ON CONFLICT DO UPDATE\n"
" SET value=excluded.value, mtime=excluded.mtime\n"
" WHERE mtime<excluded.mtime;",
zUrl, zArg, iTime
);
db_protect_pop();
}
url_unparse(&x);
}
}else
/* error MESSAGE
**
** The server is reporting an error. The client will abandon
** the sync session.
**
|
| ︙ | ︙ |