Fossil SCM

Promote the test-detach to be just "detach". Provide better help. Require user confirmation. For "fossil pull --from-parent-project" remember the URL of the last parent project pull. Remove parent-project settings on a "fossil scrub".

drh 2022-01-13 19:45 trunk
Commit b3f3a898c8dd9751632471d382ed5b0132b250c31feb5e8522e949e93a138857
3 files changed +58 -10 +1 -1 +32 -8
+58 -10
--- src/rebuild.c
+++ src/rebuild.c
@@ -745,33 +745,80 @@
745745
fossil_print("%-15s %6d\n", "Other:", g.parseCnt[CFTYPE_ANY] - subtotal);
746746
}
747747
}
748748
749749
/*
750
-** COMMAND: test-detach
751
-**
752
-** Usage: %fossil test-detach ?REPOSITORY?
753
-**
754
-** Change the project-code and make other changes in order to prevent
755
-** the repository from ever again pushing or pulling to other
756
-** repositories. Used to create a "test" repository for development
757
-** testing by cloning a working project repository.
750
+** COMMAND: detach*
751
+**
752
+** Usage: %fossil detach ?REPOSITORY?
753
+**
754
+** Change the project-code and make other changes to REPOSITORY so that
755
+** it becomes a new and distinct child project. After being detached,
756
+** REPOSITORY will not longer be able to push and pull from other clones
757
+** of the original project. However REPOSITORY will still be able to pull
758
+** from those other clones using the --from-parent-project option of the
759
+** "fossil pull" command.
760
+**
761
+** This is an experts-only command. You should not use this command unless
762
+** you fully understand what you are doing.
763
+**
764
+** The original use-case for this command was to create test repositories
765
+** from real-world working repositories that could be safely altered by
766
+** making strange commits or other changes, without having to worry that
767
+** those test changes would leak back into the original project via an
768
+** accidental auto-sync.
758769
*/
759770
void test_detach_cmd(void){
771
+ const char *zXfer[] = {
772
+ "project-name", "parent-project-name",
773
+ "project-code", "parent-project-code",
774
+ "last-sync-url", "parent-project-url",
775
+ "last-sync-pw", "parent-project-pw"
776
+ };
777
+ int i;
778
+ Blob ans;
779
+ char cReply;
760780
db_find_and_open_repository(0, 2);
781
+ prompt_user("This change will be difficult to undo. Are you sure (y/N)? ",
782
+ &ans);
783
+ cReply = blob_str(&ans)[0];
784
+ if( cReply!='y' && cReply!='Y' ) return;
761785
db_begin_transaction();
762786
db_unprotect(PROTECT_CONFIG);
787
+ for(i=0; i<ArraySize(zXfer)-1; i+=2 ){
788
+ db_multi_exec(
789
+ "REPLACE INTO config(name,value,mtime)"
790
+ " SELECT %Q, value, now() FROM config WHERE name=%Q",
791
+ zXfer[i+1], zXfer[i]
792
+ );
793
+ }
763794
db_multi_exec(
764
- "DELETE FROM config WHERE name GLOB 'last-sync-*';"
765
- "DELETE FROM config WHERE name GLOB 'sync-*:*';"
795
+ "DELETE FROM config WHERE name IN"
796
+ "(WITH pattern(x) AS (VALUES"
797
+ " ('baseurl:*'),"
798
+ " ('cert:*'),"
799
+ " ('ckout:*'),"
800
+ " ('gitpush:*'),"
801
+ " ('http-auth:*'),"
802
+ " ('last-sync-*'),"
803
+ " ('link:*'),"
804
+ " ('login-group-*'),"
805
+ " ('peer-*'),"
806
+ " ('subrepo:*'),"
807
+ " ('sync-*'),"
808
+ " ('syncfrom:*'),"
809
+ " ('syncwith:*'),"
810
+ " ('ssl-*')"
811
+ ") SELECT name FROM config, pattern WHERE name GLOB x);"
766812
"UPDATE config SET value=lower(hex(randomblob(20)))"
767813
" WHERE name='project-code';"
768814
"UPDATE config SET value='detached-' || value"
769815
" WHERE name='project-name' AND value NOT GLOB 'detached-*';"
770816
);
771817
db_protect_pop();
772818
db_end_transaction(0);
819
+ fossil_print("New project code: %s\n", db_get("project-code",""));
773820
}
774821
775822
/*
776823
** COMMAND: test-create-clusters
777824
**
@@ -929,10 +976,11 @@
929976
" ('gitpush:*'),"
930977
" ('http-auth:*'),"
931978
" ('last-sync-*'),"
932979
" ('link:*'),"
933980
" ('login-group-*'),"
981
+ " ('parent-project-*'),"
934982
" ('peer-*'),"
935983
" ('skin:*'),"
936984
" ('subrepo:*'),"
937985
" ('sync-*'),"
938986
" ('syncfrom:*'),"
939987
--- src/rebuild.c
+++ src/rebuild.c
@@ -745,33 +745,80 @@
745 fossil_print("%-15s %6d\n", "Other:", g.parseCnt[CFTYPE_ANY] - subtotal);
746 }
747 }
748
749 /*
750 ** COMMAND: test-detach
751 **
752 ** Usage: %fossil test-detach ?REPOSITORY?
753 **
754 ** Change the project-code and make other changes in order to prevent
755 ** the repository from ever again pushing or pulling to other
756 ** repositories. Used to create a "test" repository for development
757 ** testing by cloning a working project repository.
 
 
 
 
 
 
 
 
 
 
 
758 */
759 void test_detach_cmd(void){
 
 
 
 
 
 
 
 
 
760 db_find_and_open_repository(0, 2);
 
 
 
 
761 db_begin_transaction();
762 db_unprotect(PROTECT_CONFIG);
 
 
 
 
 
 
 
763 db_multi_exec(
764 "DELETE FROM config WHERE name GLOB 'last-sync-*';"
765 "DELETE FROM config WHERE name GLOB 'sync-*:*';"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
766 "UPDATE config SET value=lower(hex(randomblob(20)))"
767 " WHERE name='project-code';"
768 "UPDATE config SET value='detached-' || value"
769 " WHERE name='project-name' AND value NOT GLOB 'detached-*';"
770 );
771 db_protect_pop();
772 db_end_transaction(0);
 
773 }
774
775 /*
776 ** COMMAND: test-create-clusters
777 **
@@ -929,10 +976,11 @@
929 " ('gitpush:*'),"
930 " ('http-auth:*'),"
931 " ('last-sync-*'),"
932 " ('link:*'),"
933 " ('login-group-*'),"
 
934 " ('peer-*'),"
935 " ('skin:*'),"
936 " ('subrepo:*'),"
937 " ('sync-*'),"
938 " ('syncfrom:*'),"
939
--- src/rebuild.c
+++ src/rebuild.c
@@ -745,33 +745,80 @@
745 fossil_print("%-15s %6d\n", "Other:", g.parseCnt[CFTYPE_ANY] - subtotal);
746 }
747 }
748
749 /*
750 ** COMMAND: detach*
751 **
752 ** Usage: %fossil detach ?REPOSITORY?
753 **
754 ** Change the project-code and make other changes to REPOSITORY so that
755 ** it becomes a new and distinct child project. After being detached,
756 ** REPOSITORY will not longer be able to push and pull from other clones
757 ** of the original project. However REPOSITORY will still be able to pull
758 ** from those other clones using the --from-parent-project option of the
759 ** "fossil pull" command.
760 **
761 ** This is an experts-only command. You should not use this command unless
762 ** you fully understand what you are doing.
763 **
764 ** The original use-case for this command was to create test repositories
765 ** from real-world working repositories that could be safely altered by
766 ** making strange commits or other changes, without having to worry that
767 ** those test changes would leak back into the original project via an
768 ** accidental auto-sync.
769 */
770 void test_detach_cmd(void){
771 const char *zXfer[] = {
772 "project-name", "parent-project-name",
773 "project-code", "parent-project-code",
774 "last-sync-url", "parent-project-url",
775 "last-sync-pw", "parent-project-pw"
776 };
777 int i;
778 Blob ans;
779 char cReply;
780 db_find_and_open_repository(0, 2);
781 prompt_user("This change will be difficult to undo. Are you sure (y/N)? ",
782 &ans);
783 cReply = blob_str(&ans)[0];
784 if( cReply!='y' && cReply!='Y' ) return;
785 db_begin_transaction();
786 db_unprotect(PROTECT_CONFIG);
787 for(i=0; i<ArraySize(zXfer)-1; i+=2 ){
788 db_multi_exec(
789 "REPLACE INTO config(name,value,mtime)"
790 " SELECT %Q, value, now() FROM config WHERE name=%Q",
791 zXfer[i+1], zXfer[i]
792 );
793 }
794 db_multi_exec(
795 "DELETE FROM config WHERE name IN"
796 "(WITH pattern(x) AS (VALUES"
797 " ('baseurl:*'),"
798 " ('cert:*'),"
799 " ('ckout:*'),"
800 " ('gitpush:*'),"
801 " ('http-auth:*'),"
802 " ('last-sync-*'),"
803 " ('link:*'),"
804 " ('login-group-*'),"
805 " ('peer-*'),"
806 " ('subrepo:*'),"
807 " ('sync-*'),"
808 " ('syncfrom:*'),"
809 " ('syncwith:*'),"
810 " ('ssl-*')"
811 ") SELECT name FROM config, pattern WHERE name GLOB x);"
812 "UPDATE config SET value=lower(hex(randomblob(20)))"
813 " WHERE name='project-code';"
814 "UPDATE config SET value='detached-' || value"
815 " WHERE name='project-name' AND value NOT GLOB 'detached-*';"
816 );
817 db_protect_pop();
818 db_end_transaction(0);
819 fossil_print("New project code: %s\n", db_get("project-code",""));
820 }
821
822 /*
823 ** COMMAND: test-create-clusters
824 **
@@ -929,10 +976,11 @@
976 " ('gitpush:*'),"
977 " ('http-auth:*'),"
978 " ('last-sync-*'),"
979 " ('link:*'),"
980 " ('login-group-*'),"
981 " ('parent-project-*'),"
982 " ('peer-*'),"
983 " ('skin:*'),"
984 " ('subrepo:*'),"
985 " ('sync-*'),"
986 " ('syncfrom:*'),"
987
+1 -1
--- src/sync.c
+++ src/sync.c
@@ -208,11 +208,11 @@
208208
urlOptional = 1;
209209
urlFlags = 0;
210210
}
211211
zHttpAuth = find_option("httpauth","B",1);
212212
if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER;
213
- if( (*pSyncFlags) & SYNC_FROMPARENT ) urlFlags &= ~URL_REMEMBER;
213
+ if( (*pSyncFlags) & SYNC_FROMPARENT ) urlFlags |= URL_USE_PARENT;
214214
if( !uvOnly ){
215215
if( find_option("private",0,0)!=0 ){
216216
*pSyncFlags |= SYNC_PRIVATE;
217217
}
218218
/* The --verily option to sync, push, and pull forces extra igot cards
219219
--- src/sync.c
+++ src/sync.c
@@ -208,11 +208,11 @@
208 urlOptional = 1;
209 urlFlags = 0;
210 }
211 zHttpAuth = find_option("httpauth","B",1);
212 if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER;
213 if( (*pSyncFlags) & SYNC_FROMPARENT ) urlFlags &= ~URL_REMEMBER;
214 if( !uvOnly ){
215 if( find_option("private",0,0)!=0 ){
216 *pSyncFlags |= SYNC_PRIVATE;
217 }
218 /* The --verily option to sync, push, and pull forces extra igot cards
219
--- src/sync.c
+++ src/sync.c
@@ -208,11 +208,11 @@
208 urlOptional = 1;
209 urlFlags = 0;
210 }
211 zHttpAuth = find_option("httpauth","B",1);
212 if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER;
213 if( (*pSyncFlags) & SYNC_FROMPARENT ) urlFlags |= URL_USE_PARENT;
214 if( !uvOnly ){
215 if( find_option("private",0,0)!=0 ){
216 *pSyncFlags |= SYNC_PRIVATE;
217 }
218 /* The --verily option to sync, push, and pull forces extra igot cards
219
+32 -8
--- src/url.c
+++ src/url.c
@@ -40,10 +40,11 @@
4040
#define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
4141
#define URL_REMEMBER_PW 0x008 /* Should remember pw */
4242
#define URL_PROMPTED 0x010 /* Prompted for PW already */
4343
#define URL_OMIT_USER 0x020 /* Omit the user name from URL */
4444
#define URL_USE_CONFIG 0x040 /* Use remembered URLs from CONFIG table */
45
+#define URL_USE_PARENT 0x080 /* Use the URL of the parent project */
4546
4647
/*
4748
** The URL related data used with this subsystem.
4849
*/
4950
struct UrlData {
@@ -85,14 +86,19 @@
8586
** user Userid.
8687
** passwd Password.
8788
** hostname HOST:PORT or just HOST if port is the default.
8889
** canonical The URL in canonical form, omitting the password
8990
**
90
-** If zUrl==0, then parse the URL store in last-sync-url and last-sync-pw
91
-** of the CONFIG table. Or if zUrl is a symbolic name, look up the URL
92
-** in sync-url:%Q and sync-pw:%Q elements of the CONFIG table. But only
93
-** use the CONFIG table alternatives if the URL_FROM_CONFIG flag is set.
91
+** If zUrl==0 and URL_USE_CONFIG is set, then parse the URL stored
92
+** in last-sync-url and last-sync-pw of the CONFIG table. Or if
93
+** URL_USE_PARENT is also set, then use parent-project-url and
94
+** parent-project-pw from the CONFIG table instead of last-sync-url
95
+** and last-sync-pw.
96
+**
97
+** If zUrl is a symbolic name and URL_USE_CONFIG is true, then look up
98
+** the URL in sync-url:%Q and sync-pw:%Q elements of the CONFIG table where
99
+** %Q is the symbolic name.
94100
**
95101
** This routine differs from url_parse() in that this routine stores the
96102
** results in pUrlData and does not change the values of global variables.
97103
** The url_parse() routine puts its result in g.url.
98104
*/
@@ -104,14 +110,24 @@
104110
int i, j, c;
105111
char *zFile = 0;
106112
107113
if( urlFlags & URL_USE_CONFIG ){
108114
if( zUrl==0 || strcmp(zUrl,"default")==0 ){
109
- zUrl = db_get("last-sync-url", 0);
115
+ const char *zPwConfig = "last-sync-pw";
116
+ if( urlFlags & URL_USE_PARENT ){
117
+ zUrl = db_get("parent-project-url", 0);
118
+ if( zUrl==0 ){
119
+ zUrl = db_get("last-sync-url",0);
120
+ }else{
121
+ zPwConfig = "parent-project-pw";
122
+ }
123
+ }else{
124
+ zUrl = db_get("last-sync-url", 0);
125
+ }
110126
if( zUrl==0 ) return;
111127
if( pUrlData->passwd==0 ){
112
- pUrlData->passwd = unobscure(db_get("last-sync-pw", 0));
128
+ pUrlData->passwd = unobscure(db_get(zPwConfig, 0));
113129
}
114130
pUrlData->isAlias = 1;
115131
}else{
116132
char *zKey = sqlite3_mprintf("sync-url:%q", zUrl);
117133
char *zAlt = db_get(zKey, 0);
@@ -706,13 +722,21 @@
706722
/*
707723
** Remember the URL and password if requested.
708724
*/
709725
void url_remember(void){
710726
if( g.url.flags & URL_REMEMBER ){
711
- db_set("last-sync-url", g.url.canonical, 0);
727
+ if( g.url.flags & URL_USE_PARENT ){
728
+ db_set("parent-project-url", g.url.canonical, 0);
729
+ }else{
730
+ db_set("last-sync-url", g.url.canonical, 0);
731
+ }
712732
if( g.url.user!=0 && g.url.passwd!=0 && ( g.url.flags & URL_REMEMBER_PW ) ){
713
- db_set("last-sync-pw", obscure(g.url.passwd), 0);
733
+ if( g.url.flags & URL_USE_PARENT ){
734
+ db_set("parent-project-pw", obscure(g.url.passwd), 0);
735
+ }else{
736
+ db_set("last-sync-pw", obscure(g.url.passwd), 0);
737
+ }
714738
}
715739
}
716740
}
717741
718742
/* Preemptively prompt for a password if a username is given in the
719743
--- src/url.c
+++ src/url.c
@@ -40,10 +40,11 @@
40 #define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
41 #define URL_REMEMBER_PW 0x008 /* Should remember pw */
42 #define URL_PROMPTED 0x010 /* Prompted for PW already */
43 #define URL_OMIT_USER 0x020 /* Omit the user name from URL */
44 #define URL_USE_CONFIG 0x040 /* Use remembered URLs from CONFIG table */
 
45
46 /*
47 ** The URL related data used with this subsystem.
48 */
49 struct UrlData {
@@ -85,14 +86,19 @@
85 ** user Userid.
86 ** passwd Password.
87 ** hostname HOST:PORT or just HOST if port is the default.
88 ** canonical The URL in canonical form, omitting the password
89 **
90 ** If zUrl==0, then parse the URL store in last-sync-url and last-sync-pw
91 ** of the CONFIG table. Or if zUrl is a symbolic name, look up the URL
92 ** in sync-url:%Q and sync-pw:%Q elements of the CONFIG table. But only
93 ** use the CONFIG table alternatives if the URL_FROM_CONFIG flag is set.
 
 
 
 
 
94 **
95 ** This routine differs from url_parse() in that this routine stores the
96 ** results in pUrlData and does not change the values of global variables.
97 ** The url_parse() routine puts its result in g.url.
98 */
@@ -104,14 +110,24 @@
104 int i, j, c;
105 char *zFile = 0;
106
107 if( urlFlags & URL_USE_CONFIG ){
108 if( zUrl==0 || strcmp(zUrl,"default")==0 ){
109 zUrl = db_get("last-sync-url", 0);
 
 
 
 
 
 
 
 
 
 
110 if( zUrl==0 ) return;
111 if( pUrlData->passwd==0 ){
112 pUrlData->passwd = unobscure(db_get("last-sync-pw", 0));
113 }
114 pUrlData->isAlias = 1;
115 }else{
116 char *zKey = sqlite3_mprintf("sync-url:%q", zUrl);
117 char *zAlt = db_get(zKey, 0);
@@ -706,13 +722,21 @@
706 /*
707 ** Remember the URL and password if requested.
708 */
709 void url_remember(void){
710 if( g.url.flags & URL_REMEMBER ){
711 db_set("last-sync-url", g.url.canonical, 0);
 
 
 
 
712 if( g.url.user!=0 && g.url.passwd!=0 && ( g.url.flags & URL_REMEMBER_PW ) ){
713 db_set("last-sync-pw", obscure(g.url.passwd), 0);
 
 
 
 
714 }
715 }
716 }
717
718 /* Preemptively prompt for a password if a username is given in the
719
--- src/url.c
+++ src/url.c
@@ -40,10 +40,11 @@
40 #define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
41 #define URL_REMEMBER_PW 0x008 /* Should remember pw */
42 #define URL_PROMPTED 0x010 /* Prompted for PW already */
43 #define URL_OMIT_USER 0x020 /* Omit the user name from URL */
44 #define URL_USE_CONFIG 0x040 /* Use remembered URLs from CONFIG table */
45 #define URL_USE_PARENT 0x080 /* Use the URL of the parent project */
46
47 /*
48 ** The URL related data used with this subsystem.
49 */
50 struct UrlData {
@@ -85,14 +86,19 @@
86 ** user Userid.
87 ** passwd Password.
88 ** hostname HOST:PORT or just HOST if port is the default.
89 ** canonical The URL in canonical form, omitting the password
90 **
91 ** If zUrl==0 and URL_USE_CONFIG is set, then parse the URL stored
92 ** in last-sync-url and last-sync-pw of the CONFIG table. Or if
93 ** URL_USE_PARENT is also set, then use parent-project-url and
94 ** parent-project-pw from the CONFIG table instead of last-sync-url
95 ** and last-sync-pw.
96 **
97 ** If zUrl is a symbolic name and URL_USE_CONFIG is true, then look up
98 ** the URL in sync-url:%Q and sync-pw:%Q elements of the CONFIG table where
99 ** %Q is the symbolic name.
100 **
101 ** This routine differs from url_parse() in that this routine stores the
102 ** results in pUrlData and does not change the values of global variables.
103 ** The url_parse() routine puts its result in g.url.
104 */
@@ -104,14 +110,24 @@
110 int i, j, c;
111 char *zFile = 0;
112
113 if( urlFlags & URL_USE_CONFIG ){
114 if( zUrl==0 || strcmp(zUrl,"default")==0 ){
115 const char *zPwConfig = "last-sync-pw";
116 if( urlFlags & URL_USE_PARENT ){
117 zUrl = db_get("parent-project-url", 0);
118 if( zUrl==0 ){
119 zUrl = db_get("last-sync-url",0);
120 }else{
121 zPwConfig = "parent-project-pw";
122 }
123 }else{
124 zUrl = db_get("last-sync-url", 0);
125 }
126 if( zUrl==0 ) return;
127 if( pUrlData->passwd==0 ){
128 pUrlData->passwd = unobscure(db_get(zPwConfig, 0));
129 }
130 pUrlData->isAlias = 1;
131 }else{
132 char *zKey = sqlite3_mprintf("sync-url:%q", zUrl);
133 char *zAlt = db_get(zKey, 0);
@@ -706,13 +722,21 @@
722 /*
723 ** Remember the URL and password if requested.
724 */
725 void url_remember(void){
726 if( g.url.flags & URL_REMEMBER ){
727 if( g.url.flags & URL_USE_PARENT ){
728 db_set("parent-project-url", g.url.canonical, 0);
729 }else{
730 db_set("last-sync-url", g.url.canonical, 0);
731 }
732 if( g.url.user!=0 && g.url.passwd!=0 && ( g.url.flags & URL_REMEMBER_PW ) ){
733 if( g.url.flags & URL_USE_PARENT ){
734 db_set("parent-project-pw", obscure(g.url.passwd), 0);
735 }else{
736 db_set("last-sync-pw", obscure(g.url.passwd), 0);
737 }
738 }
739 }
740 }
741
742 /* Preemptively prompt for a password if a username is given in the
743

Keyboard Shortcuts

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