Check-in [9346f2290c]
Not logged in
Overview

SHA1 Hash:9346f2290c84084f4641a48a5e0fc813d1587251
Date: 2008-10-17 00:20:21
User: drh
Comment:Added the "all" command for things like "fossil all sync". I am not sure "all" is quite the right name for this command, so I may yet change it.
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Added src/allrepo.c version [044b203277]

@@ -1,1 +1,143 @@
+/*
+** Copyright (c) 2008 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License version 2 as published by the Free Software Foundation.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+**
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*******************************************************************************
+**
+** This file contains code to implement the "all" command-line method.
+*/
+#include "config.h"
+#include "allrepo.h"
+#include <assert.h>
+
+/*
+** The input string is a filename.  Return a new copy of this
+** filename if the filename requires quoting due to special characters
+** such as spaces in the name.
+**
+** If the filename cannot be safely quoted, return a NULL pointer.
+**
+** Space to hold the returned string is obtained from malloc.  A new
+** string is returned even if no quoting is needed.
+*/
+static char *quoteFilename(const char *zFilename){
+  int i, c;
+  int needQuote = 0;
+  for(i=0; (c = zFilename[i])!=0; i++){
+    if( c=='"' ) return 0;
+    if( isspace(c) ) needQuote = 1;
+    if( c=='\\' && zFilename[i+1]==0 ) return 0;
+    if( c=='$' ) return 0;
+  }
+  if( needQuote ){
+    return mprintf("\"%s\"", zFilename);
+  }else{
+    return mprintf("%s", zFilename);
+  }
+}
+
+
+/*
+** COMMAND: all
+**
+** Usage: %fossil add (list|pull|push|sync)
+**
+** The ~/.fossil file records the location of all repositories for a
+** user.  This command performs certain operations on all repositories
+** that can be useful before or after a period of disconnection operation.
+** Available operations are:
+**
+**    list     Display the location of all repositories
+**
+**    pull     Run a "pull" operation on all repositories
+**
+**    push     Run a "push" on all repositories
+**
+**    sync     Run a "sync" on all repositories
+*/
+void all_cmd(void){
+  int n;
+  Stmt q;
+  const char *zCmd;
+  char *zSyscmd;
+  char *zFossil;
+  char *zQFilename;
+  int nMissing;
+
+  if( g.argc<3 ){
+    usage("list|pull|push|sync");
+  }
+  n = strlen(g.argv[2]);
+  db_open_config();
+  db_prepare(&q, "SELECT substr(name, 6) FROM global_config"
+                 " WHERE substr(name, 1, 5)=='repo:' ORDER BY 1");
+  zCmd = g.argv[2];
+  if( strncmp(zCmd, "list", n)==0 ){
+    zCmd = "list";
+  }else if( strncmp(zCmd, "push", n)==0 ){
+    zCmd = "push";
+  }else if( strncmp(zCmd, "pull", n)==0 ){
+    zCmd = "pull";
+  }else if( strncmp(zCmd, "sync", n)==0 ){
+    zCmd = "sync";
+  }else{
+    fossil_fatal("\"all\" subcommand should be one of: "
+                 "list push pull sync");
+  }
+  zFossil = quoteFilename(g.argv[0]);
+  nMissing = 0;
+  while( db_step(&q)==SQLITE_ROW ){
+    const char *zFilename = db_column_text(&q, 0);
+    if( access(zFilename, 0) ){
+      nMissing++;
+      continue;
+    }
+    if( zCmd[0]=='l' ){
+      printf("%s\n", zFilename);
+      continue;
+    }
+    zQFilename = quoteFilename(zFilename);
+    zSyscmd = mprintf("%s %s -R %s -autourl",
+       zFossil, zCmd, zQFilename);
+    printf("%s\n", zSyscmd);
+    fflush(stdout);
+    system(zSyscmd);
+    free(zSyscmd);
+    free(zQFilename);
+  }
 
+  /* If any repositories hows names appear in the ~/.fossil file could not
+  ** be found, remove those names from the ~/.fossil file.
+  */
+  if( nMissing ){
+    db_begin_transaction();
+    db_reset(&q);
+    while( db_step(&q)==SQLITE_ROW ){
+      const char *zFilename = db_column_text(&q, 0);
+      if( access(zFilename, 0) ){
+        const char *zRepo = mprintf("repo:%s", zFilename);
+        db_unset(zRepo, 1);
+        free(zRepo);
+      }
+    }
+    db_finalize(&q);
+    db_end_transaction(0);
+  }
+}

Modified src/checkin.c from [425f4bbcea] to [4a866358e3].

@@ -46,11 +46,13 @@
     int isDeleted = db_column_int(&q, 1);
     int isChnged = db_column_int(&q,2);
     int isNew = db_column_int(&q,3)==0;
     char *zFullName = mprintf("%s/%s", g.zLocalRoot, zPathname);
     blob_append(report, zPrefix, nPrefix);
-    if( access(zFullName, 0) ){
+    if( isDeleted ){
+      blob_appendf(report, "DELETED  %s\n", zPathname);
+    }else if( access(zFullName, 0) ){
       blob_appendf(report, "MISSING  %s\n", zPathname);
     }else if( isNew ){
       blob_appendf(report, "ADDED    %s\n", zPathname);
     }else if( isDeleted ){
       blob_appendf(report, "DELETED  %s\n", zPathname);
@@ -398,10 +400,11 @@
   if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
     fossil_fatal("no such user: %s", g.zLogin);
   }
 
   db_begin_transaction();
+  db_record_repository_filename(0);
   rc = unsaved_changes();
   if( rc==0 && !isAMerge && !forceFlag ){
     fossil_panic("nothing has changed");
   }
 

Modified src/db.c from [b821ea8fc7] to [d2615a7db8].

@@ -555,10 +555,11 @@
 ** it does not already exist.
 */
 void db_open_config(void){
   char *zDbName;
   const char *zHome;
+  if( g.configOpen ) return;
 #ifdef __MINGW32__
   zHome = getenv("LOCALAPPDATA");
   if( zHome==0 ){
     zHome = getenv("APPDATA");
     if( zHome==0 ){
@@ -575,11 +576,10 @@
   /* . filenames give some window systems problems and many apps problems */
   zDbName = mprintf("%//_fossil", zHome);
 #else
   zDbName = mprintf("%s/.fossil", zHome);
 #endif
-  if( g.configOpen ) return;
   if( file_size(zDbName)<1024*3 ){
     db_init_database(zDbName, zConfigSchema, (char*)0);
   }
   db_open_or_attach(zDbName, "configdb");
   g.configOpen = 1;
@@ -1120,10 +1120,31 @@
 void db_lset_int(const char *zName, int value){
   db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
 }
 
 /*
+** Record the name of a local repository in the global_config() database.
+** The repostiroy filename %s is recorded as an entry with a "name" field
+** of the following form:
+**
+**       repo:%s
+**
+** The value field is set to 1.
+*/
+void db_record_repository_filename(const char *zName){
+  if( zName==0 ){
+    if( !g.localOpen ) return;
+    zName = db_lget("repository", 0);
+  }
+  db_multi_exec(
+     "INSERT OR IGNORE INTO global_config(name,value)"
+     "VALUES('repo:%q',1)",
+     zName
+  );
+}
+
+/*
 ** COMMAND: open
 **
 ** Usage: open FILENAME
 **
 ** Open a connection to the local repository in FILENAME.  A checkout
@@ -1144,10 +1165,11 @@
   file_canonical_name(g.argv[2], &path);
   db_open_repository(blob_str(&path));
   db_init_database("./_FOSSIL_", zLocalSchema, (char*)0);
   db_open_local();
   db_lset("repository", blob_str(&path));
+  db_record_repository_filename(blob_str(&path));
   vid = db_int(0, "SELECT pid FROM plink y"
                   " WHERE NOT EXISTS(SELECT 1 FROM plink x WHERE x.cid=y.pid)");
   if( vid==0 ){
     db_lset_int("checkout", 1);
   }else{

Modified src/main.mk from [441865bbd2] to [4242635d97].

@@ -13,10 +13,11 @@
 
 
 SRC = \
   $(SRCDIR)/add.c \
   $(SRCDIR)/admin.c \
+  $(SRCDIR)/allrepo.c \
   $(SRCDIR)/bag.c \
   $(SRCDIR)/blob.c \
   $(SRCDIR)/branch.c \
   $(SRCDIR)/browse.c \
   $(SRCDIR)/cgi.c \
@@ -79,10 +80,11 @@
   $(SRCDIR)/zip.c
 
 TRANS_SRC = \
   add_.c \
   admin_.c \
+  allrepo_.c \
   bag_.c \
   blob_.c \
   branch_.c \
   browse_.c \
   cgi_.c \
@@ -145,10 +147,11 @@
   zip_.c
 
 OBJ = \
   add.o \
   admin.o \
+  allrepo.o \
   bag.o \
   blob.o \
   branch.o \
   browse.o \
   cgi.o \
@@ -249,16 +252,16 @@
 	# noop
 
 clean:
 	rm -f *.o *_.c $(APPNAME) VERSION.h
 	rm -f translate makeheaders mkindex page_index.h headers
-	rm -f add.h admin.h bag.h blob.h branch.h browse.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h configure.h construct.h content.h db.h delta.h deltacmd.h descendants.h diff.h diffcmd.h doc.h encode.h file.h http.h info.h login.h main.h manifest.h md5.h merge.h merge3.h my_page.h name.h pivot.h pqueue.h printf.h rebuild.h report.h rss.h schema.h setup.h sha1.h shun.h stat.h style.h sync.h tag.h tagview.h th_main.h timeline.h tkt.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h winhttp.h xfer.h zip.h
+	rm -f add.h admin.h allrepo.h bag.h blob.h branch.h browse.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h configure.h construct.h content.h db.h delta.h deltacmd.h descendants.h diff.h diffcmd.h doc.h encode.h file.h http.h info.h login.h main.h manifest.h md5.h merge.h merge3.h my_page.h name.h pivot.h pqueue.h printf.h rebuild.h report.h rss.h schema.h setup.h sha1.h shun.h stat.h style.h sync.h tag.h tagview.h th_main.h timeline.h tkt.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h winhttp.h xfer.h zip.h
 
 page_index.h: $(TRANS_SRC) mkindex
 	./mkindex $(TRANS_SRC) >$@
-headers:	page_index.h makeheaders $(TRANS_SRC) VERSION.h
-	./makeheaders  add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h VERSION.h
+headers:	page_index.h makeheaders VERSION.h
+	./makeheaders  add_.c:add.h admin_.c:admin.h allrepo_.c:allrepo.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h VERSION.h
 	touch headers
 headers: Makefile
 Makefile:
 add_.c:	$(SRCDIR)/add.c $(SRCDIR)/VERSION translate
 	./translate $(SRCDIR)/add.c | sed -f $(SRCDIR)/VERSION >add_.c
@@ -272,10 +275,17 @@
 
 admin.o:	admin_.c admin.h  $(SRCDIR)/config.h
 	$(XTCC) -o admin.o -c admin_.c
 
 admin.h:	headers
+allrepo_.c:	$(SRCDIR)/allrepo.c $(SRCDIR)/VERSION translate
+	./translate $(SRCDIR)/allrepo.c | sed -f $(SRCDIR)/VERSION >allrepo_.c
+
+allrepo.o:	allrepo_.c allrepo.h  $(SRCDIR)/config.h
+	$(XTCC) -o allrepo.o -c allrepo_.c
+
+allrepo.h:	headers
 bag_.c:	$(SRCDIR)/bag.c $(SRCDIR)/VERSION translate
 	./translate $(SRCDIR)/bag.c | sed -f $(SRCDIR)/VERSION >bag_.c
 
 bag.o:	bag_.c bag.h  $(SRCDIR)/config.h
 	$(XTCC) -o bag.o -c bag_.c

Modified src/makemake.tcl from [cffe151e34] to [a62edbeae5].

@@ -7,10 +7,11 @@
 # "translate" and "makeheaders"
 #
 set src {
   add
   admin
+  allrepo
   bag
   blob
   branch
   browse
   cgi

Modified src/sync.c from [4404bbdd39] to [c4538ea75a].

@@ -72,18 +72,20 @@
 ** of a server to sync against.  If no argument is given, use the
 ** most recently synced URL.  Remember the current URL for next time.
 */
 void process_sync_args(void){
   const char *zUrl = 0;
+  int urlOptional = find_option("autourl",0,0)!=0;
   url_proxy_options();
   db_find_and_open_repository(1);
   if( g.argc==2 ){
     zUrl = db_get("last-sync-url", 0);
   }else if( g.argc==3 ){
     zUrl = g.argv[2];
   }
   if( zUrl==0 ){
+    if( urlOptional ) exit(0);
     usage("URL");
   }
   url_parse(zUrl);
   if( g.urlIsFile ){
     fossil_fatal("network sync only");

Modified src/xfer.c from [4b3dcbe795] to [cdde3a92c3].

@@ -818,10 +818,13 @@
 
   assert( pushFlag || pullFlag || cloneFlag || configMask );
   assert( !g.urlIsFile );          /* This only works for networking */
 
   db_begin_transaction();
+  if( pullFlag || cloneFlag ){
+    db_record_repository_filename(0);
+  }
   db_multi_exec(
     "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
   );
   blobarray_zero(xfer.aToken, count(xfer.aToken));
   blob_zero(&send);