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 merge the changes in the current
dbda8d6ce9 2007-07-21       drh: ** checkout into a different version and switch to that version.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #include "config.h"
dbda8d6ce9 2007-07-21       drh: #include "update.h"
dbda8d6ce9 2007-07-21       drh: #include <assert.h>
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** COMMAND: update
dbda8d6ce9 2007-07-21       drh: **
6607844a01 2007-08-18       drh: ** Usage: %fossil update ?VERSION?
6607844a01 2007-08-18       drh: **
dbda8d6ce9 2007-07-21       drh: ** The optional argument is a version that should become the current
dbda8d6ce9 2007-07-21       drh: ** version.  If the argument is omitted, then use the leaf of the
6607844a01 2007-08-18       drh: ** tree that begins with the current version, if there is only a
6607844a01 2007-08-18       drh: ** single leaf.
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: ** This command is different from the "checkout" in that edits are
6607844a01 2007-08-18       drh: ** not overwritten.  Edits are merged into the new version.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void update_cmd(void){
dbda8d6ce9 2007-07-21       drh:   int vid;              /* Current version */
dbda8d6ce9 2007-07-21       drh:   int tid;              /* Target version - version we are changing to */
dbda8d6ce9 2007-07-21       drh:   Stmt q;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( g.argc!=3 && g.argc!=2 ){
dbda8d6ce9 2007-07-21       drh:     usage("?VERSION?");
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:   if( vid==0 ){
dbda8d6ce9 2007-07-21       drh:     vid = 1;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( db_exists("SELECT 1 FROM vmerge") ){
dbda8d6ce9 2007-07-21       drh:     fossil_fatal("cannot update an uncommitted merge");
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( g.argc==3 ){
dbda8d6ce9 2007-07-21       drh:     tid = name_to_rid(g.argv[2]);
dbda8d6ce9 2007-07-21       drh:     if( tid==0 ){
dbda8d6ce9 2007-07-21       drh:       fossil_fatal("not a version: %s", g.argv[2]);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", tid) ){
dbda8d6ce9 2007-07-21       drh:       fossil_fatal("not a version: %s", g.argv[2]);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     compute_leaves(vid);
dbda8d6ce9 2007-07-21       drh:     if( db_int(0, "SELECT count(*) FROM leaves")>1 ){
dbda8d6ce9 2007-07-21       drh:       fossil_fatal("multiple descendents");
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     tid = db_int(0, "SELECT rid FROM leaves");
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   db_begin_transaction();
dbda8d6ce9 2007-07-21       drh:   vfile_check_signature(vid);
dbda8d6ce9 2007-07-21       drh:   load_vfile_from_rid(tid);
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /*
dbda8d6ce9 2007-07-21       drh:   ** The record.fn field is used to match files against each other.  The
dbda8d6ce9 2007-07-21       drh:   ** FV table contains one row for each each unique filename in
dbda8d6ce9 2007-07-21       drh:   ** in the current checkout, the pivot, and the version being merged.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   db_multi_exec(
dbda8d6ce9 2007-07-21       drh:     "DROP TABLE IF EXISTS fv;"
dbda8d6ce9 2007-07-21       drh:     "CREATE TEMP TABLE fv("
dbda8d6ce9 2007-07-21       drh:     "  fn TEXT PRIMARY KEY,"      /* The filename */
dbda8d6ce9 2007-07-21       drh:     "  idv INTEGER,"              /* VFILE entry for current version */
dbda8d6ce9 2007-07-21       drh:     "  idt INTEGER,"              /* VFILE entry for target version */
dbda8d6ce9 2007-07-21       drh:     "  chnged BOOLEAN,"           /* True if current version has been edited */
dbda8d6ce9 2007-07-21       drh:     "  ridv INTEGER,"             /* Record ID for current version */
dbda8d6ce9 2007-07-21       drh:     "  ridt INTEGER "             /* Record ID for target */
dbda8d6ce9 2007-07-21       drh:     ");"
dbda8d6ce9 2007-07-21       drh:     "INSERT OR IGNORE INTO fv"
dbda8d6ce9 2007-07-21       drh:     " SELECT pathname, 0, 0, 0, 0, 0 FROM vfile"
dbda8d6ce9 2007-07-21       drh:   );
dbda8d6ce9 2007-07-21       drh:   db_prepare(&q,
dbda8d6ce9 2007-07-21       drh:     "SELECT id, pathname, rid FROM vfile"
dbda8d6ce9 2007-07-21       drh:     " WHERE vid=%d", tid
dbda8d6ce9 2007-07-21       drh:   );
dbda8d6ce9 2007-07-21       drh:   while( db_step(&q)==SQLITE_ROW ){
dbda8d6ce9 2007-07-21       drh:     int id = db_column_int(&q, 0);
dbda8d6ce9 2007-07-21       drh:     const char *fn = db_column_text(&q, 1);
dbda8d6ce9 2007-07-21       drh:     int rid = db_column_int(&q, 2);
dbda8d6ce9 2007-07-21       drh:     db_multi_exec(
dbda8d6ce9 2007-07-21       drh:       "UPDATE fv SET idt=%d, ridt=%d WHERE fn=%Q",
dbda8d6ce9 2007-07-21       drh:       id, rid, fn
dbda8d6ce9 2007-07-21       drh:     );
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   db_finalize(&q);
dbda8d6ce9 2007-07-21       drh:   db_prepare(&q,
dbda8d6ce9 2007-07-21       drh:     "SELECT id, pathname, rid, chnged FROM vfile"
dbda8d6ce9 2007-07-21       drh:     " WHERE vid=%d", vid
dbda8d6ce9 2007-07-21       drh:   );
dbda8d6ce9 2007-07-21       drh:   while( db_step(&q)==SQLITE_ROW ){
dbda8d6ce9 2007-07-21       drh:     int id = db_column_int(&q, 0);
dbda8d6ce9 2007-07-21       drh:     const char *fn = db_column_text(&q, 1);
dbda8d6ce9 2007-07-21       drh:     int rid = db_column_int(&q, 2);
dbda8d6ce9 2007-07-21       drh:     int chnged = db_column_int(&q, 3);
dbda8d6ce9 2007-07-21       drh:     db_multi_exec(
dbda8d6ce9 2007-07-21       drh:       "UPDATE fv SET idv=%d, ridv=%d, chnged=%d WHERE fn=%Q",
dbda8d6ce9 2007-07-21       drh:       id, rid, chnged, fn
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:   db_prepare(&q,
dbda8d6ce9 2007-07-21       drh:     "SELECT fn, idv, ridv, idt, ridt, chnged FROM fv ORDER BY 1"
dbda8d6ce9 2007-07-21       drh:   );
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:     int idv = db_column_int(&q, 1);
dbda8d6ce9 2007-07-21       drh:     int ridv = db_column_int(&q, 2);
dbda8d6ce9 2007-07-21       drh:     int idt = db_column_int(&q, 3);
dbda8d6ce9 2007-07-21       drh:     int ridt = db_column_int(&q, 4);
dbda8d6ce9 2007-07-21       drh:     int chnged = db_column_int(&q, 5);
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     if( idv>0 && ridv==0 && idt>0 ){
dbda8d6ce9 2007-07-21       drh:       /* Conflict.  This file has been added to the current checkout
dbda8d6ce9 2007-07-21       drh:       ** but also exists in the target checkout.  Use the current version.
dbda8d6ce9 2007-07-21       drh:       */
dbda8d6ce9 2007-07-21       drh:       printf("CONFLICT %s\n", zName);
dbda8d6ce9 2007-07-21       drh:     }else if( idt>0 && idv==0 ){
dbda8d6ce9 2007-07-21       drh:       /* File added in the target. */
dbda8d6ce9 2007-07-21       drh:       printf("ADD %s\n", zName);
dbda8d6ce9 2007-07-21       drh:       vfile_to_disk(0, idt, 0);
dbda8d6ce9 2007-07-21       drh:     }else if( idt>0 && idv>0 && ridt!=ridv && chnged==0 ){
dbda8d6ce9 2007-07-21       drh:       /* The file is unedited.  Change it to the target version */
dbda8d6ce9 2007-07-21       drh:       printf("UPDATE %s\n", zName);
dbda8d6ce9 2007-07-21       drh:       vfile_to_disk(0, idt, 0);
dbda8d6ce9 2007-07-21       drh:     }else if( idt==0 && idv>0 ){
fe6ee8a431 2007-08-08       drh:       if( chnged ){
fe6ee8a431 2007-08-08       drh:         printf("CONFLICT %s\n", zName);
fe6ee8a431 2007-08-08       drh:       }else{
fe6ee8a431 2007-08-08       drh:         char *zFullPath;
fe6ee8a431 2007-08-08       drh:         printf("REMOVE %s\n", zName);
fe6ee8a431 2007-08-08       drh:         zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
fe6ee8a431 2007-08-08       drh:         unlink(zFullPath);
fe6ee8a431 2007-08-08       drh:         free(zFullPath);
fe6ee8a431 2007-08-08       drh:       }
dbda8d6ce9 2007-07-21       drh:     }else if( idt>0 && idv>0 && ridt!=ridv && chnged ){
dbda8d6ce9 2007-07-21       drh:       /* Merge the changes in the current tree into the target version */
dbda8d6ce9 2007-07-21       drh:       Blob e, r, t, v;
dbda8d6ce9 2007-07-21       drh:       char *zFullPath;
dbda8d6ce9 2007-07-21       drh:       printf("MERGE %s\n", zName);
dbda8d6ce9 2007-07-21       drh:       zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
dbda8d6ce9 2007-07-21       drh:       content_get(ridt, &t);
dbda8d6ce9 2007-07-21       drh:       content_get(ridv, &v);
dbda8d6ce9 2007-07-21       drh:       blob_zero(&e);
dbda8d6ce9 2007-07-21       drh:       blob_read_from_file(&e, zFullPath);
dbda8d6ce9 2007-07-21       drh:       blob_merge(&v, &e, &t, &r);
dbda8d6ce9 2007-07-21       drh:       blob_write_to_file(&r, zFullPath);
dbda8d6ce9 2007-07-21       drh:       free(zFullPath);
dbda8d6ce9 2007-07-21       drh:       blob_reset(&v);
dbda8d6ce9 2007-07-21       drh:       blob_reset(&e);
dbda8d6ce9 2007-07-21       drh:       blob_reset(&t);
dbda8d6ce9 2007-07-21       drh:       blob_reset(&r);
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:   ** Clean up the mid and pid VFILE entries.  Then commit the changes.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   db_multi_exec("DELETE FROM vfile WHERE vid!=%d", tid);
a040ae6e17 2007-08-08       drh:   manifest_to_disk(tid);
dbda8d6ce9 2007-07-21       drh:   db_lset_int("checkout", tid);
dbda8d6ce9 2007-07-21       drh:   db_end_transaction(0);
dbda8d6ce9 2007-07-21       drh: }