File Annotation
Not logged in
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Copyright (c) 2007 D. Richard Hipp
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This program is free software; you can redistribute it and/or
dbda8d6ce9 2007-07-21       drh: ** modify it under the terms of the GNU General Public
dbda8d6ce9 2007-07-21       drh: ** License version 2 as published by the Free Software Foundation.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This program is distributed in the hope that it will be useful,
dbda8d6ce9 2007-07-21       drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
dbda8d6ce9 2007-07-21       drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
dbda8d6ce9 2007-07-21       drh: ** General Public License for more details.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** You should have received a copy of the GNU General Public
dbda8d6ce9 2007-07-21       drh: ** License along with this library; if not, write to the
dbda8d6ce9 2007-07-21       drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
dbda8d6ce9 2007-07-21       drh: ** Boston, MA  02111-1307, USA.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Author contact information:
dbda8d6ce9 2007-07-21       drh: **   drh@hwaci.com
dbda8d6ce9 2007-07-21       drh: **   http://www.hwaci.com/drh/
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: *******************************************************************************
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This file contains code used to check-out versions of the project
dbda8d6ce9 2007-07-21       drh: ** from the local repository.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #include "config.h"
dbda8d6ce9 2007-07-21       drh: #include "checkin.h"
dbda8d6ce9 2007-07-21       drh: #include <assert.h>
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Generate text describing all changes.  Prepend zPrefix to each line
dbda8d6ce9 2007-07-21       drh: ** of output.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** We assume that vfile_check_signature has been run.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void status_report(Blob *report, const char *zPrefix){
dbda8d6ce9 2007-07-21       drh:   Stmt q;
dbda8d6ce9 2007-07-21       drh:   int nPrefix = strlen(zPrefix);
22552fb803 2007-08-03       dan:   db_prepare(&q,
22552fb803 2007-08-03       dan:     "SELECT pathname, deleted, chnged, rid FROM vfile "
22552fb803 2007-08-03       dan:     "WHERE file_is_selected(id) AND (chnged OR deleted OR rid=0) ORDER BY 1"
22552fb803 2007-08-03       dan:   );
dbda8d6ce9 2007-07-21       drh:   while( db_step(&q)==SQLITE_ROW ){
dbda8d6ce9 2007-07-21       drh:     const char *zPathname = db_column_text(&q,0);
dbda8d6ce9 2007-07-21       drh:     int isDeleted = db_column_int(&q, 1);
dbda8d6ce9 2007-07-21       drh:     int isChnged = db_column_int(&q,2);
dbda8d6ce9 2007-07-21       drh:     int isNew = db_column_int(&q,3)==0;
371dd6574c 2007-12-04       drh:     char *zFullName = mprintf("%s/%s", g.zLocalRoot, zPathname);
dbda8d6ce9 2007-07-21       drh:     blob_append(report, zPrefix, nPrefix);
371dd6574c 2007-12-04       drh:     if( access(zFullName, 0) ){
371dd6574c 2007-12-04       drh:       blob_appendf(report, "MISSING  %s\n", zPathname);
371dd6574c 2007-12-04       drh:     }else if( isNew ){
dbda8d6ce9 2007-07-21       drh:       blob_appendf(report, "ADDED    %s\n", zPathname);
dbda8d6ce9 2007-07-21       drh:     }else if( isDeleted ){
dbda8d6ce9 2007-07-21       drh:       blob_appendf(report, "DELETED  %s\n", zPathname);
dbda8d6ce9 2007-07-21       drh:     }else if( isChnged==2 ){
dbda8d6ce9 2007-07-21       drh:       blob_appendf(report, "UPDATED_BY_MERGE %s\n", zPathname);
dbda8d6ce9 2007-07-21       drh:     }else if( isChnged==3 ){
dbda8d6ce9 2007-07-21       drh:       blob_appendf(report, "ADDED_BY_MERGE %s\n", zPathname);
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       blob_appendf(report, "EDITED   %s\n", zPathname);
dbda8d6ce9 2007-07-21       drh:     }
371dd6574c 2007-12-04       drh:     free(zFullName);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   db_finalize(&q);
dbda8d6ce9 2007-07-21       drh:   db_prepare(&q, "SELECT uuid FROM vmerge JOIN blob ON merge=rid"
dbda8d6ce9 2007-07-21       drh:                  " WHERE id=0");
dbda8d6ce9 2007-07-21       drh:   while( db_step(&q)==SQLITE_ROW ){
dbda8d6ce9 2007-07-21       drh:     blob_append(report, zPrefix, nPrefix);
dbda8d6ce9 2007-07-21       drh:     blob_appendf(report, "MERGED_WITH %s\n", db_column_text(&q, 0));
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   db_finalize(&q);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** COMMAND: changes
dbda8d6ce9 2007-07-21       drh: **
c9fdb846fb 2007-08-18       drh: ** Usage: %fossil changes
c9fdb846fb 2007-08-18       drh: ** Report on the edit status of all files in the current checkout.
c9fdb846fb 2007-08-18       drh: ** See also the "status" and "extra" commands.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void changes_cmd(void){
dbda8d6ce9 2007-07-21       drh:   Blob report;
dbda8d6ce9 2007-07-21       drh:   int vid;
dbda8d6ce9 2007-07-21       drh:   db_must_be_within_tree();
dbda8d6ce9 2007-07-21       drh:   blob_zero(&report);
dbda8d6ce9 2007-07-21       drh:   vid = db_lget_int("checkout", 0);
dbda8d6ce9 2007-07-21       drh:   vfile_check_signature(vid);
dbda8d6ce9 2007-07-21       drh:   status_report(&report, "");
dbda8d6ce9 2007-07-21       drh:   blob_write_to_file(&report, "-");
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** COMMAND: status
c9fdb846fb 2007-08-18       drh: ** Usage: %fossil status
c9fdb846fb 2007-08-18       drh: ** Report on the status of the current checkout.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void status_cmd(void){
dbda8d6ce9 2007-07-21       drh:   int vid;
dbda8d6ce9 2007-07-21       drh:   db_must_be_within_tree();
dbda8d6ce9 2007-07-21       drh:        /* 012345678901234 */
dbda8d6ce9 2007-07-21       drh:   printf("repository:   %s\n", db_lget("repository",""));
dbda8d6ce9 2007-07-21       drh:   printf("local-root:   %s\n", g.zLocalRoot);
dbda8d6ce9 2007-07-21       drh:   printf("server-code:  %s\n", db_get("server-code", ""));
dbda8d6ce9 2007-07-21       drh:   vid = db_lget_int("checkout", 0);
dbda8d6ce9 2007-07-21       drh:   if( vid ){
dbda8d6ce9 2007-07-21       drh:     show_common_info(vid, "checkout:", 0);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   changes_cmd();
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** COMMAND: ls
c9fdb846fb 2007-08-18       drh: ** Usage: %fossil ls
c9fdb846fb 2007-08-18       drh: ** Show the names of all files in the current checkout
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void ls_cmd(void){
dbda8d6ce9 2007-07-21       drh:   int vid;
dbda8d6ce9 2007-07-21       drh:   Stmt q;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   db_must_be_within_tree();
dbda8d6ce9 2007-07-21       drh:   vid = db_lget_int("checkout", 0);
dbda8d6ce9 2007-07-21       drh:   vfile_check_signature(vid);
dbda8d6ce9 2007-07-21       drh:   db_prepare(&q, "SELECT pathname, deleted, rid, chnged FROM vfile"
dbda8d6ce9 2007-07-21       drh:                  " ORDER BY 1");
dbda8d6ce9 2007-07-21       drh:   while( db_step(&q)==SQLITE_ROW ){
dbda8d6ce9 2007-07-21       drh:     const char *zPathname = db_column_text(&q,0);
dbda8d6ce9 2007-07-21       drh:     int isDeleted = db_column_int(&q, 1);
dbda8d6ce9 2007-07-21       drh:     int isNew = db_column_int(&q,2)==0;
dbda8d6ce9 2007-07-21       drh:     int chnged = db_column_int(&q,3);
dbda8d6ce9 2007-07-21       drh:     if( isNew ){
dbda8d6ce9 2007-07-21       drh:       printf("ADDED     %s\n", zPathname);
dbda8d6ce9 2007-07-21       drh:     }else if( isDeleted ){
dbda8d6ce9 2007-07-21       drh:       printf("DELETED   %s\n", zPathname);
dbda8d6ce9 2007-07-21       drh:     }else if( chnged ){
dbda8d6ce9 2007-07-21       drh:       printf("EDITED    %s\n", zPathname);
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       printf("UNCHANGED %s\n", zPathname);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   db_finalize(&q);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** COMMAND: extra
c9fdb846fb 2007-08-18       drh: ** Usage: %fossil extra
dbda8d6ce9 2007-07-21       drh: ** Print a list of all files in the source tree that are not part of
c9fdb846fb 2007-08-18       drh: ** the current checkout.  See also the "clean" command.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void extra_cmd(void){
dbda8d6ce9 2007-07-21       drh:   Blob path;
dbda8d6ce9 2007-07-21       drh:   Stmt q;
dbda8d6ce9 2007-07-21       drh:   db_must_be_within_tree();
dbda8d6ce9 2007-07-21       drh:   db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
dbda8d6ce9 2007-07-21       drh:   chdir(g.zLocalRoot);
dbda8d6ce9 2007-07-21       drh:   blob_zero(&path);
dbda8d6ce9 2007-07-21       drh:   vfile_scan(0, &path);
77327ae14e 2007-08-08       drh:   db_prepare(&q,
77327ae14e 2007-08-08       drh:       "SELECT x FROM sfile"
95e17f4e3f 2007-08-25       drh:       " WHERE x NOT IN ('manifest','manifest.uuid','_FOSSIL_')"
77327ae14e 2007-08-08       drh:       " ORDER BY 1");
dbda8d6ce9 2007-07-21       drh:   while( db_step(&q)==SQLITE_ROW ){
dbda8d6ce9 2007-07-21       drh:     printf("%s\n", db_column_text(&q, 0));
c9fdb846fb 2007-08-18       drh:   }
c9fdb846fb 2007-08-18       drh:   db_finalize(&q);
c9fdb846fb 2007-08-18       drh: }
c9fdb846fb 2007-08-18       drh: 
c9fdb846fb 2007-08-18       drh: /*
c9fdb846fb 2007-08-18       drh: ** COMMAND: clean
8372cc0b81 2007-09-22       jnc: ** Usage: %fossil clean ?-all
c9fdb846fb 2007-08-18       drh: ** Delete all "extra" files in the source tree.  "Extra" files are
c9fdb846fb 2007-08-18       drh: ** files that are not officially part of the checkout.  See also
8372cc0b81 2007-09-22       jnc: ** the "extra" command. This operation cannot be undone.
8372cc0b81 2007-09-22       jnc: **
8372cc0b81 2007-09-22       jnc: ** You will be prompted before removing each file. If you are
8372cc0b81 2007-09-22       jnc: ** sure you wish to remove all "extra" files you can specify the
8372cc0b81 2007-09-22       jnc: ** optional -all flag.
c9fdb846fb 2007-08-18       drh: */
c9fdb846fb 2007-08-18       drh: void clean_cmd(void){
8372cc0b81 2007-09-22       jnc:   int allFlag;
c9fdb846fb 2007-08-18       drh:   Blob path;
c9fdb846fb 2007-08-18       drh:   Stmt q;
8372cc0b81 2007-09-22       jnc:   allFlag = find_option("all","a",0)!=0;
c9fdb846fb 2007-08-18       drh:   db_must_be_within_tree();
c9fdb846fb 2007-08-18       drh:   db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
c9fdb846fb 2007-08-18       drh:   chdir(g.zLocalRoot);
c9fdb846fb 2007-08-18       drh:   blob_zero(&path);
c9fdb846fb 2007-08-18       drh:   vfile_scan(0, &path);
c9fdb846fb 2007-08-18       drh:   db_prepare(&q,
c9fdb846fb 2007-08-18       drh:       "SELECT %Q || x FROM sfile"
95e17f4e3f 2007-08-25       drh:       " WHERE x NOT IN ('manifest','manifest.uuid','_FOSSIL_')"
c9fdb846fb 2007-08-18       drh:       " ORDER BY 1", g.zLocalRoot);
c9fdb846fb 2007-08-18       drh:   while( db_step(&q)==SQLITE_ROW ){
8372cc0b81 2007-09-22       jnc:     if( allFlag ){
8372cc0b81 2007-09-22       jnc:       unlink(db_column_text(&q, 0));
820a1a1a53 2007-09-23       drh:     }else{
820a1a1a53 2007-09-23       drh:       Blob ans;
820a1a1a53 2007-09-23       drh:       char *prompt = mprintf("remove unmanaged file \"%s\" [y/N]? ",
820a1a1a53 2007-09-23       drh:                               db_column_text(&q, 0));
820a1a1a53 2007-09-23       drh:       blob_zero(&ans);
820a1a1a53 2007-09-23       drh:       prompt_user(prompt, &ans);
820a1a1a53 2007-09-23       drh:       if( blob_str(&ans)[0]=='y' ){
820a1a1a53 2007-09-23       drh:         unlink(db_column_text(&q, 0));
820a1a1a53 2007-09-23       drh:       }
8372cc0b81 2007-09-22       jnc:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   db_finalize(&q);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Prepare a commit comment.  Let the user modify it using the
dbda8d6ce9 2007-07-21       drh: ** editor specified in the global_config table or either
dbda8d6ce9 2007-07-21       drh: ** the VISUAL or EDITOR environment variable.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Store the final commit comment in pComment.  pComment is assumed
dbda8d6ce9 2007-07-21       drh: ** to be uninitialized - any prior content is overwritten.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void prepare_commit_comment(Blob *pComment){
dbda8d6ce9 2007-07-21       drh:   const char *zEditor;
dbda8d6ce9 2007-07-21       drh:   char *zCmd;
dbda8d6ce9 2007-07-21       drh:   char *zFile;
dbda8d6ce9 2007-07-21       drh:   Blob text, line;
dbda8d6ce9 2007-07-21       drh:   char *zComment;
dbda8d6ce9 2007-07-21       drh:   int i;
dbda8d6ce9 2007-07-21       drh:   blob_set(&text,
dbda8d6ce9 2007-07-21       drh:     "\n# Enter comments on this commit.  Lines beginning with # are ignored\n"
dbda8d6ce9 2007-07-21       drh:     "#\n"
dbda8d6ce9 2007-07-21       drh:   );
dbda8d6ce9 2007-07-21       drh:   status_report(&text, "# ");
134e2aeccc 2007-09-28       drh:   zEditor = db_get("editor", 0);
dbda8d6ce9 2007-07-21       drh:   if( zEditor==0 ){
dbda8d6ce9 2007-07-21       drh:     zEditor = getenv("VISUAL");
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( zEditor==0 ){
dbda8d6ce9 2007-07-21       drh:     zEditor = getenv("EDITOR");
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( zEditor==0 ){
dbda8d6ce9 2007-07-21       drh:     zEditor = "ed";
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   zFile = db_text(0, "SELECT '%qci-comment-' || hex(randomblob(6)) || '.txt'",
dbda8d6ce9 2007-07-21       drh:                    g.zLocalRoot);
dbda8d6ce9 2007-07-21       drh:   blob_write_to_file(&text, zFile);
8372cc0b81 2007-09-22       jnc:   zCmd = mprintf("%s \"%s\"", zEditor, zFile);
c9fdb846fb 2007-08-18       drh:   printf("%s\n", zCmd);
dbda8d6ce9 2007-07-21       drh:   if( system(zCmd) ){
dbda8d6ce9 2007-07-21       drh:     fossil_panic("editor aborted");
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   blob_reset(&text);
dbda8d6ce9 2007-07-21       drh:   blob_read_from_file(&text, zFile);
dbda8d6ce9 2007-07-21       drh:   unlink(zFile);
dbda8d6ce9 2007-07-21       drh:   free(zFile);
dbda8d6ce9 2007-07-21       drh:   blob_zero(pComment);
dbda8d6ce9 2007-07-21       drh:   while( blob_line(&text, &line) ){
dbda8d6ce9 2007-07-21       drh:     int i, n;
dbda8d6ce9 2007-07-21       drh:     char *z;
dbda8d6ce9 2007-07-21       drh:     n = blob_size(&line);
dbda8d6ce9 2007-07-21       drh:     z = blob_buffer(&line);
dbda8d6ce9 2007-07-21       drh:     for(i=0; i<n && isspace(z[i]);  i++){}
dbda8d6ce9 2007-07-21       drh:     if( i<n && z[i]=='#' ) continue;
f030c0aea7 2007-08-30       drh:     if( i<n || blob_size(pComment)>0 ){
f030c0aea7 2007-08-30       drh:       blob_appendf(pComment, "%b", &line);
f030c0aea7 2007-08-30       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   blob_reset(&text);
dbda8d6ce9 2007-07-21       drh:   zComment = blob_str(pComment);
dbda8d6ce9 2007-07-21       drh:   i = strlen(zComment);
dbda8d6ce9 2007-07-21       drh:   while( i>0 && isspace(zComment[i-1]) ){ i--; }
dbda8d6ce9 2007-07-21       drh:   blob_resize(pComment, i);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
22552fb803 2007-08-03       dan: ** Populate the Global.aCommitFile[] based on the command line arguments
22552fb803 2007-08-03       dan: ** to a [commit] command. Global.aCommitFile is an array of integers
22552fb803 2007-08-03       dan: ** sized at (N+1), where N is the number of arguments passed to [commit].
22552fb803 2007-08-03       dan: ** The contents are the [id] values from the vfile table corresponding
22552fb803 2007-08-03       dan: ** to the filenames passed as arguments.
22552fb803 2007-08-03       dan: **
22552fb803 2007-08-03       dan: ** The last element of aCommitFile[] is always 0 - indicating the end
22552fb803 2007-08-03       dan: ** of the array.
22552fb803 2007-08-03       dan: **
22552fb803 2007-08-03       dan: ** If there were no arguments passed to [commit], aCommitFile is not
22552fb803 2007-08-03       dan: ** allocated and remains NULL. Other parts of the code interpret this
22552fb803 2007-08-03       dan: ** to mean "all files".
22552fb803 2007-08-03       dan: */
22552fb803 2007-08-03       dan: void select_commit_files(void){
22552fb803 2007-08-03       dan:   if( g.argc>2 ){
22552fb803 2007-08-03       dan:     int ii;
22552fb803 2007-08-03       dan:     Blob b;
aafd536a5c 2007-08-04       drh:     blob_zero(&b);
22552fb803 2007-08-03       dan:     g.aCommitFile = malloc(sizeof(int)*(g.argc-1));
22552fb803 2007-08-03       dan: 
22552fb803 2007-08-03       dan:     for(ii=2; ii<g.argc; ii++){
22552fb803 2007-08-03       dan:       int iId;
22552fb803 2007-08-03       dan:       if( !file_tree_name(g.argv[ii], &b) ){
22552fb803 2007-08-03       dan:         fossil_fatal("file is not in tree: %s", g.argv[ii]);
22552fb803 2007-08-03       dan:       }
22552fb803 2007-08-03       dan:       iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b));
22552fb803 2007-08-03       dan:       if( iId<0 ){
22552fb803 2007-08-03       dan:         fossil_fatal("fossil knows nothing about: %s", g.argv[ii]);
22552fb803 2007-08-03       dan:       }
22552fb803 2007-08-03       dan:       g.aCommitFile[ii-2] = iId;
aafd536a5c 2007-08-04       drh:       blob_reset(&b);
22552fb803 2007-08-03       dan:     }
22552fb803 2007-08-03       dan:     g.aCommitFile[ii-2] = 0;
22552fb803 2007-08-03       dan:   }
22552fb803 2007-08-03       dan: }
22552fb803 2007-08-03       dan: 
22552fb803 2007-08-03       dan: /*
dbda8d6ce9 2007-07-21       drh: ** COMMAND: commit
dbda8d6ce9 2007-07-21       drh: **
c9fdb846fb 2007-08-18       drh: ** Usage: %fossil commit ?-m COMMENT? ?--nosign? ?FILE...?
22552fb803 2007-08-03       dan: **
dbda8d6ce9 2007-07-21       drh: ** Create a new version containing all of the changes in the current
c9fdb846fb 2007-08-18       drh: ** checkout.  You will be prompted to enter a check-in comment unless
c9fdb846fb 2007-08-18       drh: ** the "-m" option is used to specify a command line.  You will be
c9fdb846fb 2007-08-18       drh: ** prompted for your GPG passphrase in order to sign the new manifest
c9fdb846fb 2007-08-18       drh: ** unless the "--nosign" options is used.  All files that have
c9fdb846fb 2007-08-18       drh: ** changed will be committed unless some subset of files is specified
c9fdb846fb 2007-08-18       drh: ** on the command line.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void commit_cmd(void){
dbda8d6ce9 2007-07-21       drh:   int rc;
41561125cd 2007-09-26       jnc:   int vid, nrid, nvid, wouldFork=0;
dbda8d6ce9 2007-07-21       drh:   Blob comment;
9a9cd81738 2007-08-09       drh:   const char *zComment;
dbda8d6ce9 2007-07-21       drh:   Stmt q;
dbda8d6ce9 2007-07-21       drh:   Stmt q2;
dbda8d6ce9 2007-07-21       drh:   char *zUuid, *zDate;
6aff11f03f 2007-08-03       drh:   int noSign = 0;        /* True to omit signing the manifest using GPG */
4c82c7773f 2007-08-30       drh:   int isAMerge = 0;      /* True if checking in a merge */
fff234b77c 2007-09-25       drh:   int forceFlag = 0;     /* Force a fork */
dbda8d6ce9 2007-07-21       drh:   char *zManifestFile;   /* Name of the manifest file */
dbda8d6ce9 2007-07-21       drh:   Blob manifest;
741aac4d4e 2007-08-25       drh:   Blob muuid;            /* Manifest uuid */
dbda8d6ce9 2007-07-21       drh:   Blob mcksum;           /* Self-checksum on the manifest */
dbda8d6ce9 2007-07-21       drh:   Blob cksum1, cksum2;   /* Before and after commit checksums */
3945057916 2007-08-01       drh:   Blob cksum1b;          /* Checksum recorded in the manifest */
3945057916 2007-08-01       drh: 
9a9cd81738 2007-08-09       drh:   noSign = find_option("nosign","",0)!=0;
9a9cd81738 2007-08-09       drh:   zComment = find_option("comment","m",1);
fff234b77c 2007-09-25       drh:   forceFlag = find_option("force", "r", 0)!=0;
dbda8d6ce9 2007-07-21       drh:   db_must_be_within_tree();
a21806dcf3 2007-10-07       jnc:   noSign = db_get_int("omitsign", 0)|noSign;
6aff11f03f 2007-08-03       drh:   verify_all_options();
fff234b77c 2007-09-25       drh: 
fff234b77c 2007-09-25       drh:   /*
fff234b77c 2007-09-25       drh:   ** Autosync if requested.
fff234b77c 2007-09-25       drh:   */
fff234b77c 2007-09-25       drh:   autosync(1);
22552fb803 2007-08-03       dan: 
22552fb803 2007-08-03       dan:   /* There are two ways this command may be executed. If there are
22552fb803 2007-08-03       dan:   ** no arguments following the word "commit", then all modified files
22552fb803 2007-08-03       dan:   ** in the checked out directory are committed. If one or more arguments
22552fb803 2007-08-03       dan:   ** follows "commit", then only those files are committed.
22552fb803 2007-08-03       dan:   **
22552fb803 2007-08-03       dan:   ** After the following function call has returned, the Global.aCommitFile[]
22552fb803 2007-08-03       dan:   ** array is allocated to contain the "id" field from the vfile table
22552fb803 2007-08-03       dan:   ** for each file to be committed. Or, if aCommitFile is NULL, all files
22552fb803 2007-08-03       dan:   ** should be committed.
22552fb803 2007-08-03       dan:   */
22552fb803 2007-08-03       dan:   select_commit_files();
4c82c7773f 2007-08-30       drh:   isAMerge = db_exists("SELECT 1 FROM vmerge");
4c82c7773f 2007-08-30       drh:   if( g.aCommitFile && isAMerge ){
aafd536a5c 2007-08-04       drh:     fossil_fatal("cannot do a partial commit of a merge");
aafd536a5c 2007-08-04       drh:   }
22552fb803 2007-08-03       dan: 
dbda8d6ce9 2007-07-21       drh:   user_select();
dbda8d6ce9 2007-07-21       drh:   db_begin_transaction();
dbda8d6ce9 2007-07-21       drh:   rc = unsaved_changes();
fff234b77c 2007-09-25       drh:   if( rc==0 && !isAMerge && !forceFlag ){
dbda8d6ce9 2007-07-21       drh:     fossil_panic("nothing has changed");
dbda8d6ce9 2007-07-21       drh:   }
22552fb803 2007-08-03       dan: 
22552fb803 2007-08-03       dan:   /* If one or more files that were named on the command line have not
22552fb803 2007-08-03       dan:   ** been modified, bail out now.
22552fb803 2007-08-03       dan:   */
22552fb803 2007-08-03       dan:   if( g.aCommitFile ){
22552fb803 2007-08-03       dan:     Blob unmodified;
22552fb803 2007-08-03       dan:     memset(&unmodified, 0, sizeof(Blob));
22552fb803 2007-08-03       dan:     blob_init(&unmodified, 0, 0);
22552fb803 2007-08-03       dan:     db_blob(&unmodified,
22552fb803 2007-08-03       dan:       "SELECT pathname FROM vfile WHERE chnged = 0 AND file_is_selected(id)"
22552fb803 2007-08-03       dan:     );
22552fb803 2007-08-03       dan:     if( strlen(blob_str(&unmodified)) ){
22552fb803 2007-08-03       dan:       fossil_panic("file %s has not changed", blob_str(&unmodified));
22552fb803 2007-08-03       dan:     }
22552fb803 2007-08-03       dan:   }
22552fb803 2007-08-03       dan: 
dbda8d6ce9 2007-07-21       drh:   vid = db_lget_int("checkout", 0);
41561125cd 2007-09-26       jnc:   if( db_exists("SELECT 1 FROM plink WHERE pid=%d", vid) ){
41561125cd 2007-09-26       jnc:     wouldFork=1;
41561125cd 2007-09-26       jnc:     if( forceFlag==0 && db_get_int("safemerge", 0)==0 ){
41561125cd 2007-09-26       jnc:       fossil_fatal("would fork.  use -f or --force");
41561125cd 2007-09-26       jnc:     }
fff234b77c 2007-09-25       drh:   }
dbda8d6ce9 2007-07-21       drh:   vfile_aggregate_checksum_disk(vid, &cksum1);
9a9cd81738 2007-08-09       drh:   if( zComment ){
9a9cd81738 2007-08-09       drh:     blob_zero(&comment);
9a9cd81738 2007-08-09       drh:     blob_append(&comment, zComment, -1);
9a9cd81738 2007-08-09       drh:   }else{
9a9cd81738 2007-08-09       drh:     prepare_commit_comment(&comment);
9a9cd81738 2007-08-09       drh:   }
22552fb803 2007-08-03       dan: 
22552fb803 2007-08-03       dan:   /* Step 1: Insert records for all modified files into the blob
22552fb803 2007-08-03       dan:   ** table. If there were arguments passed to this command, only
22552fb803 2007-08-03       dan:   ** the identified fils are inserted (if they have been modified).
22552fb803 2007-08-03       dan:   */
dbda8d6ce9 2007-07-21       drh:   db_prepare(&q,
22552fb803 2007-08-03       dan:     "SELECT id, %Q || pathname, mrid FROM vfile "
22552fb803 2007-08-03       dan:     "WHERE chnged==1 AND NOT deleted AND file_is_selected(id)"
22552fb803 2007-08-03       dan:     , g.zLocalRoot
22552fb803 2007-08-03       dan:   );
dbda8d6ce9 2007-07-21       drh:   while( db_step(&q)==SQLITE_ROW ){
dbda8d6ce9 2007-07-21       drh:     int id, rid;
dbda8d6ce9 2007-07-21       drh:     const char *zFullname;
dbda8d6ce9 2007-07-21       drh:     Blob content;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     id = db_column_int(&q, 0);
dbda8d6ce9 2007-07-21       drh:     zFullname = db_column_text(&q, 1);
dbda8d6ce9 2007-07-21       drh:     rid = db_column_int(&q, 2);
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     blob_zero(&content);
dbda8d6ce9 2007-07-21       drh:     blob_read_from_file(&content, zFullname);
573a464cb7 2007-08-10       drh:     nrid = content_put(&content, 0, 0);
dbda8d6ce9 2007-07-21       drh:     if( rid>0 ){
dbda8d6ce9 2007-07-21       drh:       content_deltify(rid, nrid, 0);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d WHERE id=%d", nrid,nrid,id);
e1c1877c99 2007-09-08       drh:     db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   db_finalize(&q);
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* Create the manifest */
dbda8d6ce9 2007-07-21       drh:   blob_zero(&manifest);
1871a93dd4 2007-08-30       drh:   if( blob_size(&comment)==0 ){
1871a93dd4 2007-08-30       drh:     blob_append(&comment, "(no comment)", -1);
1871a93dd4 2007-08-30       drh:   }
dbda8d6ce9 2007-07-21       drh:   blob_appendf(&manifest, "C %F\n", blob_str(&comment));
dbda8d6ce9 2007-07-21       drh:   zDate = db_text(0, "SELECT datetime('now')");
dbda8d6ce9 2007-07-21       drh:   zDate[10] = 'T';
dbda8d6ce9 2007-07-21       drh:   blob_appendf(&manifest, "D %s\n", zDate);
dbda8d6ce9 2007-07-21       drh:   db_prepare(&q,
5c3e87171a 2007-08-01       drh:     "SELECT pathname, uuid FROM vfile JOIN blob ON vfile.mrid=blob.rid"
ac1dea8eac 2007-07-24       drh:     " WHERE NOT deleted AND vfile.vid=%d"
dbda8d6ce9 2007-07-21       drh:     " ORDER BY 1", vid);
dbda8d6ce9 2007-07-21       drh:   while( db_step(&q)==SQLITE_ROW ){
dbda8d6ce9 2007-07-21       drh:     const char *zName = db_column_text(&q, 0);
dbda8d6ce9 2007-07-21       drh:     const char *zUuid = db_column_text(&q, 1);
dbda8d6ce9 2007-07-21       drh:     blob_appendf(&manifest, "F %F %s\n", zName, zUuid);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   db_finalize(&q);
dbda8d6ce9 2007-07-21       drh:   zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
dbda8d6ce9 2007-07-21       drh:   blob_appendf(&manifest, "P %s", zUuid);
22552fb803 2007-08-03       dan: 
22552fb803 2007-08-03       dan:   db_prepare(&q2, "SELECT merge FROM vmerge WHERE id=:id");
dbda8d6ce9 2007-07-21       drh:   db_bind_int(&q2, ":id", 0);
dbda8d6ce9 2007-07-21       drh:   while( db_step(&q2)==SQLITE_ROW ){
dbda8d6ce9 2007-07-21       drh:     int mid = db_column_int(&q2, 0);
dbda8d6ce9 2007-07-21       drh:     zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
dbda8d6ce9 2007-07-21       drh:     if( zUuid ){
dbda8d6ce9 2007-07-21       drh:       blob_appendf(&manifest, " %s", zUuid);
dbda8d6ce9 2007-07-21       drh:       free(zUuid);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   db_reset(&q2);
22552fb803 2007-08-03       dan: 
dbda8d6ce9 2007-07-21       drh:   blob_appendf(&manifest, "\n");
dbda8d6ce9 2007-07-21       drh:   blob_appendf(&manifest, "R %b\n", &cksum1);
dbda8d6ce9 2007-07-21       drh:   blob_appendf(&manifest, "U %F\n", g.zLogin);
dbda8d6ce9 2007-07-21       drh:   md5sum_blob(&manifest, &mcksum);
dbda8d6ce9 2007-07-21       drh:   blob_appendf(&manifest, "Z %b\n", &mcksum);
dbda8d6ce9 2007-07-21       drh:   zManifestFile = mprintf("%smanifest", g.zLocalRoot);
6aff11f03f 2007-08-03       drh:   if( !noSign && clearsign(&manifest, &manifest) ){
e37451d9c2 2007-08-01       drh:     Blob ans;
e37451d9c2 2007-08-01       drh:     blob_zero(&ans);
e37451d9c2 2007-08-01       drh:     prompt_user("unable to sign manifest.  continue [y/N]? ", &ans);
e37451d9c2 2007-08-01       drh:     if( blob_str(&ans)[0]!='y' ){
e37451d9c2 2007-08-01       drh:       db_end_transaction(1);
e37451d9c2 2007-08-01       drh:       exit(1);
e37451d9c2 2007-08-01       drh:     }
e37451d9c2 2007-08-01       drh:   }
e37451d9c2 2007-08-01       drh:   blob_write_to_file(&manifest, zManifestFile);
dbda8d6ce9 2007-07-21       drh:   blob_reset(&manifest);
dbda8d6ce9 2007-07-21       drh:   blob_read_from_file(&manifest, zManifestFile);
dbda8d6ce9 2007-07-21       drh:   free(zManifestFile);
573a464cb7 2007-08-10       drh:   nvid = content_put(&manifest, 0, 0);
dbda8d6ce9 2007-07-21       drh:   if( nvid==0 ){
dbda8d6ce9 2007-07-21       drh:     fossil_panic("trouble committing manifest: %s", g.zErrMsg);
dbda8d6ce9 2007-07-21       drh:   }
e1c1877c99 2007-09-08       drh:   db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid);
dbda8d6ce9 2007-07-21       drh:   manifest_crosslink(nvid, &manifest);
dbda8d6ce9 2007-07-21       drh:   content_deltify(vid, nvid, 0);
dbda8d6ce9 2007-07-21       drh:   zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid);
dbda8d6ce9 2007-07-21       drh:   printf("New_Version: %s\n", zUuid);
741aac4d4e 2007-08-25       drh:   zManifestFile = mprintf("%smanifest.uuid", g.zLocalRoot);
741aac4d4e 2007-08-25       drh:   blob_zero(&muuid);
741aac4d4e 2007-08-25       drh:   blob_appendf(&muuid, "%s\n", zUuid);
741aac4d4e 2007-08-25       drh:   blob_write_to_file(&muuid, zManifestFile);
741aac4d4e 2007-08-25       drh:   free(zManifestFile);
741aac4d4e 2007-08-25       drh:   blob_reset(&muuid);
741aac4d4e 2007-08-25       drh: 
dbda8d6ce9 2007-07-21       drh: 
22552fb803 2007-08-03       dan:   /* Update the vfile and vmerge tables */
22552fb803 2007-08-03       dan:   db_multi_exec(
22552fb803 2007-08-03       dan:     "DELETE FROM vfile WHERE (vid!=%d OR deleted) AND file_is_selected(id);"
22552fb803 2007-08-03       dan:     "DELETE FROM vmerge WHERE file_is_selected(id) OR id=0;"
22552fb803 2007-08-03       dan:     "UPDATE vfile SET vid=%d;"
22552fb803 2007-08-03       dan:     "UPDATE vfile SET rid=mrid, chnged=0, deleted=0 WHERE file_is_selected(id);"
22552fb803 2007-08-03       dan:     , vid, nvid
22552fb803 2007-08-03       dan:   );
dbda8d6ce9 2007-07-21       drh:   db_lset_int("checkout", nvid);
dbda8d6ce9 2007-07-21       drh: 
22552fb803 2007-08-03       dan:   /* Verify that the repository checksum matches the expected checksum
22552fb803 2007-08-03       dan:   ** calculated before the checkin started (and stored as the R record
22552fb803 2007-08-03       dan:   ** of the manifest file).
22552fb803 2007-08-03       dan:   */
dbda8d6ce9 2007-07-21       drh:   vfile_aggregate_checksum_repository(nvid, &cksum2);
dbda8d6ce9 2007-07-21       drh:   if( blob_compare(&cksum1, &cksum2) ){
dbda8d6ce9 2007-07-21       drh:     fossil_panic("tree checksum does not match repository after commit");
dbda8d6ce9 2007-07-21       drh:   }
22552fb803 2007-08-03       dan: 
22552fb803 2007-08-03       dan:   /* Verify that the manifest checksum matches the expected checksum */
3945057916 2007-08-01       drh:   vfile_aggregate_checksum_manifest(nvid, &cksum2, &cksum1b);
3945057916 2007-08-01       drh:   if( blob_compare(&cksum1, &cksum1b) ){
3945057916 2007-08-01       drh:     fossil_panic("manifest checksum does not agree with manifest: "
3945057916 2007-08-01       drh:                  "%b versus %b", &cksum1, &cksum1b);
3945057916 2007-08-01       drh:   }
5c3e87171a 2007-08-01       drh:   if( blob_compare(&cksum1, &cksum2) ){
3945057916 2007-08-01       drh:     fossil_panic("tree checksum does not match manifest after commit: "
3945057916 2007-08-01       drh:                  "%b versus %b", &cksum1, &cksum2);
5c3e87171a 2007-08-01       drh:   }
22552fb803 2007-08-03       dan: 
22552fb803 2007-08-03       dan:   /* Verify that the commit did not modify any disk images. */
dbda8d6ce9 2007-07-21       drh:   vfile_aggregate_checksum_disk(nvid, &cksum2);
dbda8d6ce9 2007-07-21       drh:   if( blob_compare(&cksum1, &cksum2) ){
dbda8d6ce9 2007-07-21       drh:     fossil_panic("tree checksums before and after commit do not match");
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
a36177bcce 2007-09-11       drh:   /* Clear the undo/redo stack */
a36177bcce 2007-09-11       drh:   undo_reset();
a36177bcce 2007-09-11       drh: 
dbda8d6ce9 2007-07-21       drh:   /* Commit */
dbda8d6ce9 2007-07-21       drh:   db_end_transaction(0);
0431f14edf 2007-09-25       jnc: 
41561125cd 2007-09-26       jnc:   if( wouldFork==0 ){
41561125cd 2007-09-26       jnc:     /* Do an autosync push if requested. If wouldFork == 1, then they either
41561125cd 2007-09-26       jnc:     ** forced this commit or safe merge is on, and this commit did indeed
41561125cd 2007-09-26       jnc:     ** create a fork. In this case, we want the user to merge before sending
41561125cd 2007-09-26       jnc:     ** their new commit back to the rest of the world, so do not auto-push.
41561125cd 2007-09-26       jnc:     */
41561125cd 2007-09-26       jnc:     autosync(0);
41561125cd 2007-09-26       jnc:   }else{
41561125cd 2007-09-26       jnc:     printf("Warning: commit caused a fork to occur. Please merge and push\n");
41561125cd 2007-09-26       jnc:     printf("         your changes as soon as possible.\n");
0431f14edf 2007-09-25       jnc:   }
dbda8d6ce9 2007-07-21       drh: }