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 "checkout.h" dbda8d6ce9 2007-07-21 drh: #include <assert.h> dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Check to see if there is an existing checkout that has been dbda8d6ce9 2007-07-21 drh: ** modified. Return values: dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** 0: There is an existing checkout but it is unmodified dbda8d6ce9 2007-07-21 drh: ** 1: There is a modified checkout - there are unsaved changes dbda8d6ce9 2007-07-21 drh: ** 2: There is no existing checkout dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int unsaved_changes(void){ dbda8d6ce9 2007-07-21 drh: int vid; 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 ) return 2; dbda8d6ce9 2007-07-21 drh: vfile_check_signature(vid); e146d800ac 2008-11-09 drh: return db_exists("SELECT 1 FROM vfile WHERE chnged" e146d800ac 2008-11-09 drh: " OR coalesce(origname!=pathname,0)"); e146d800ac 2008-11-09 drh: } e146d800ac 2008-11-09 drh: 695b1c7563 2009-04-29 bch: 695b1c7563 2009-04-29 bch: /* 695b1c7563 2009-04-29 bch: ** zTarget is guaranteed to be a UUID. It might be the UUID of a ticket. 695b1c7563 2009-04-29 bch: ** If it is, store in *pClosed a true or false depending on whether or not 695b1c7563 2009-04-29 bch: ** the ticket is closed and return true. If zTarget 695b1c7563 2009-04-29 bch: ** is not the UUID of a ticket, return false. 695b1c7563 2009-04-29 bch: */ 695b1c7563 2009-04-29 bch: static int is_ticket( 695b1c7563 2009-04-29 bch: const char *zTarget, /* Ticket UUID */ 695b1c7563 2009-04-29 bch: int *pClosed /* True if the ticket is closed */ 695b1c7563 2009-04-29 bch: ){ 5d49162a31 2009-04-29 bch: fprintf(stderr,"I'm in is_ticket\n"); 5d49162a31 2009-04-29 bch: 695b1c7563 2009-04-29 bch: static Stmt q; 695b1c7563 2009-04-29 bch: static int once = 1; 695b1c7563 2009-04-29 bch: int n; 695b1c7563 2009-04-29 bch: int rc; 695b1c7563 2009-04-29 bch: char zLower[UUID_SIZE+1]; 695b1c7563 2009-04-29 bch: char zUpper[UUID_SIZE+1]; 695b1c7563 2009-04-29 bch: n = strlen(zTarget); 695b1c7563 2009-04-29 bch: memcpy(zLower, zTarget, n+1); 695b1c7563 2009-04-29 bch: canonical16(zLower, n+1); 695b1c7563 2009-04-29 bch: memcpy(zUpper, zLower, n+1); 695b1c7563 2009-04-29 bch: zUpper[n-1]++; 695b1c7563 2009-04-29 bch: if( once ){ 695b1c7563 2009-04-29 bch: const char *zClosedExpr = db_get("ticket-closed-expr", "status='Closed'"); 695b1c7563 2009-04-29 bch: db_static_prepare(&q, 695b1c7563 2009-04-29 bch: "SELECT %s FROM ticket " 695b1c7563 2009-04-29 bch: " WHERE tkt_uuid>=:lwr AND tkt_uuid<:upr", 695b1c7563 2009-04-29 bch: zClosedExpr 695b1c7563 2009-04-29 bch: ); 695b1c7563 2009-04-29 bch: once = 0; 695b1c7563 2009-04-29 bch: } 695b1c7563 2009-04-29 bch: db_bind_text(&q, ":lwr", zLower); 695b1c7563 2009-04-29 bch: db_bind_text(&q, ":upr", zUpper); 695b1c7563 2009-04-29 bch: if( db_step(&q)==SQLITE_ROW ){ 695b1c7563 2009-04-29 bch: rc = 1; 695b1c7563 2009-04-29 bch: *pClosed = db_column_int(&q, 0); 695b1c7563 2009-04-29 bch: }else{ 695b1c7563 2009-04-29 bch: rc = 0; 695b1c7563 2009-04-29 bch: } 695b1c7563 2009-04-29 bch: db_reset(&q); 695b1c7563 2009-04-29 bch: return rc; 695b1c7563 2009-04-29 bch: } 695b1c7563 2009-04-29 bch: 4fff366109 2009-04-19 bch: /* 4fff366109 2009-04-19 bch: ** Check to see if the requested co is in fact "checkout-able" 4fff366109 2009-04-19 bch: ** Return values: 4fff366109 2009-04-19 bch: ** 0: Not checkout-able (does not exist, or is not an on-disk artifact) 4fff366109 2009-04-19 bch: ** 1: Is checkout-able. 4fff366109 2009-04-19 bch: */ 4fff366109 2009-04-19 bch: int checkoutable(const char *zName){ 695b1c7563 2009-04-29 bch: int rc; /* return code */ 695b1c7563 2009-04-29 bch: int throwaway; 695b1c7563 2009-04-29 bch: 695b1c7563 2009-04-29 bch: rc = !is_ticket(zName, &throwaway); 5d49162a31 2009-04-29 bch: fprintf(stderr,"rc is: %d\n", rc); 695b1c7563 2009-04-29 bch: return(rc); 695b1c7563 2009-04-29 bch: 4fff366109 2009-04-19 bch: Blob uuid; 4fff366109 2009-04-19 bch: const char *rid=(char *)NULL; 4fff366109 2009-04-19 bch: Stmt q; // db query 4fff366109 2009-04-19 bch: char *zSQL; //build-up sql 4fff366109 2009-04-19 bch: 4fff366109 2009-04-19 bch: // zSQL = mprintf(); 4fff366109 2009-04-19 bch: 4fff366109 2009-04-19 bch: // [create sql statement] 4fff366109 2009-04-19 bch: // db_prepare(&q,sqlstmt); 4fff366109 2009-04-19 bch: 4fff366109 2009-04-19 bch: blob_init(&uuid, zName, -1); 4fff366109 2009-04-19 bch: if( name_to_uuid(&uuid, 1) ){ 4fff366109 2009-04-19 bch: fossil_panic(g.zErrMsg); 4fff366109 2009-04-19 bch: } 4fff366109 2009-04-19 bch: 4fff366109 2009-04-19 bch: /* nParent=db_text(0,"select rid from blob where uuid=%s",uuid.nameofobj); */ 4fff366109 2009-04-19 bch: 4fff366109 2009-04-19 bch: /* int nParent = db_column_int(q, somenum); */ 4fff366109 2009-04-19 bch: return rc; dbda8d6ce9 2007-07-21 drh: } 4fff366109 2009-04-19 bch: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Undo the current check-out. Unlink all files from the disk. dbda8d6ce9 2007-07-21 drh: ** Clear the VFILE table. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: void uncheckout(int vid){ dbda8d6ce9 2007-07-21 drh: if( vid==0 ) return; dbda8d6ce9 2007-07-21 drh: vfile_unlink(vid); dbda8d6ce9 2007-07-21 drh: db_multi_exec("DELETE FROM vfile WHERE vid=%d", vid); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Given the abbreviated UUID name of a version, load the content of that dbda8d6ce9 2007-07-21 drh: ** version in the VFILE table. Return the VID for the version. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** If anything goes wrong, panic. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int load_vfile(const char *zName){ dbda8d6ce9 2007-07-21 drh: Blob uuid; dbda8d6ce9 2007-07-21 drh: int vid; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: blob_init(&uuid, zName, -1); dbda8d6ce9 2007-07-21 drh: if( name_to_uuid(&uuid, 1) ){ dbda8d6ce9 2007-07-21 drh: fossil_panic(g.zErrMsg); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: vid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &uuid); dbda8d6ce9 2007-07-21 drh: if( vid==0 ){ dbda8d6ce9 2007-07-21 drh: fossil_panic("no such version: %s", g.argv[2]); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: load_vfile_from_rid(vid); dbda8d6ce9 2007-07-21 drh: return vid; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Load a vfile from a record ID. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: void load_vfile_from_rid(int vid){ dbda8d6ce9 2007-07-21 drh: Blob manifest; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if( db_exists("SELECT 1 FROM vfile WHERE vid=%d", vid) ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: content_get(vid, &manifest); dbda8d6ce9 2007-07-21 drh: vfile_build(vid, &manifest); dbda8d6ce9 2007-07-21 drh: blob_reset(&manifest); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* a040ae6e17 2007-08-08 drh: ** Read the manifest file given by vid out of the repository a040ae6e17 2007-08-08 drh: ** and store it in the root of the local check-out. a040ae6e17 2007-08-08 drh: */ a040ae6e17 2007-08-08 drh: void manifest_to_disk(int vid){ a040ae6e17 2007-08-08 drh: char *zManFile; a040ae6e17 2007-08-08 drh: Blob manifest; 95e17f4e3f 2007-08-25 drh: Blob hash; 33c31f73cd 2008-02-21 drh: Blob filename; 33c31f73cd 2008-02-21 drh: int baseLen; 33c31f73cd 2008-02-21 drh: int i; 33c31f73cd 2008-02-21 drh: Manifest m; a040ae6e17 2007-08-08 drh: a040ae6e17 2007-08-08 drh: blob_zero(&manifest); a040ae6e17 2007-08-08 drh: zManFile = mprintf("%smanifest", g.zLocalRoot); a040ae6e17 2007-08-08 drh: content_get(vid, &manifest); a040ae6e17 2007-08-08 drh: blob_write_to_file(&manifest, zManFile); a040ae6e17 2007-08-08 drh: free(zManFile); 95e17f4e3f 2007-08-25 drh: blob_zero(&hash); 95e17f4e3f 2007-08-25 drh: sha1sum_blob(&manifest, &hash); 95e17f4e3f 2007-08-25 drh: zManFile = mprintf("%smanifest.uuid", g.zLocalRoot); 95e17f4e3f 2007-08-25 drh: blob_append(&hash, "\n", 1); 95e17f4e3f 2007-08-25 drh: blob_write_to_file(&hash, zManFile); 95e17f4e3f 2007-08-25 drh: free(zManFile); 95e17f4e3f 2007-08-25 drh: blob_reset(&hash); 33c31f73cd 2008-02-21 drh: manifest_parse(&m, &manifest); 33c31f73cd 2008-02-21 drh: blob_zero(&filename); 33c31f73cd 2008-02-21 drh: blob_appendf(&filename, "%s/", g.zLocalRoot); 33c31f73cd 2008-02-21 drh: baseLen = blob_size(&filename); 33c31f73cd 2008-02-21 drh: for(i=0; i<m.nFile; i++){ 33c31f73cd 2008-02-21 drh: int isExe; 33c31f73cd 2008-02-21 drh: blob_append(&filename, m.aFile[i].zName, -1); 33c31f73cd 2008-02-21 drh: isExe = m.aFile[i].zPerm && strstr(m.aFile[i].zPerm, "x"); 33c31f73cd 2008-02-21 drh: file_setexe(blob_str(&filename), isExe); 33c31f73cd 2008-02-21 drh: blob_resize(&filename, baseLen); 33c31f73cd 2008-02-21 drh: } 33c31f73cd 2008-02-21 drh: blob_reset(&filename); 33c31f73cd 2008-02-21 drh: manifest_clear(&m); a040ae6e17 2007-08-08 drh: } a040ae6e17 2007-08-08 drh: a040ae6e17 2007-08-08 drh: /* dbda8d6ce9 2007-07-21 drh: ** COMMAND: checkout a89b436bc9 2009-02-11 bharder: ** COMMAND: co c9fdb846fb 2007-08-18 drh: ** c9fdb846fb 2007-08-18 drh: ** Usage: %fossil checkout VERSION ?-f|--force? 6b85fd173e 2008-05-10 drh: ** c9fdb846fb 2007-08-18 drh: ** Check out a version specified on the command-line. This command c9fdb846fb 2007-08-18 drh: ** will not overwrite edited files in the current checkout unless c9fdb846fb 2007-08-18 drh: ** the --force option appears on the command-line. dbda8d6ce9 2007-07-21 drh: ** c9fdb846fb 2007-08-18 drh: ** See also the "update" command. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: void checkout_cmd(void){ dbda8d6ce9 2007-07-21 drh: int forceFlag; dbda8d6ce9 2007-07-21 drh: int noWrite; dbda8d6ce9 2007-07-21 drh: int vid, prior; 3945057916 2007-08-01 drh: Blob cksum1, cksum1b, cksum2; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: db_must_be_within_tree(); dbda8d6ce9 2007-07-21 drh: db_begin_transaction(); dbda8d6ce9 2007-07-21 drh: forceFlag = find_option("force","f",0)!=0; dbda8d6ce9 2007-07-21 drh: noWrite = find_option("dontwrite",0,0)!=0; dbda8d6ce9 2007-07-21 drh: if( g.argc!=3 ) usage("?--force? VERSION"); dbda8d6ce9 2007-07-21 drh: if( !forceFlag && unsaved_changes()==1 ){ 4452576730 2007-08-11 drh: fossil_fatal("there are unsaved changes in the current checkout"); c9fdb846fb 2007-08-18 drh: } ab6a293182 2009-04-19 bch: if(!checkoutable(g.argv[2])){ 4fff366109 2009-04-19 bch: fossil_fatal("the VERSION you requested is not a checkout-able artifact"); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( forceFlag ){ dbda8d6ce9 2007-07-21 drh: db_multi_exec("DELETE FROM vfile"); dbda8d6ce9 2007-07-21 drh: prior = 0; dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: prior = db_lget_int("checkout",0); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: vid = load_vfile(g.argv[2]); dbda8d6ce9 2007-07-21 drh: if( prior==vid ){ dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( !noWrite ){ dbda8d6ce9 2007-07-21 drh: uncheckout(prior); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); dbda8d6ce9 2007-07-21 drh: if( !noWrite ){ dbda8d6ce9 2007-07-21 drh: vfile_to_disk(vid, 0, 1); a040ae6e17 2007-08-08 drh: manifest_to_disk(vid); dbda8d6ce9 2007-07-21 drh: db_lset_int("checkout", vid); a36177bcce 2007-09-11 drh: undo_reset(); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: db_multi_exec("DELETE FROM vmerge"); 3945057916 2007-08-01 drh: vfile_aggregate_checksum_manifest(vid, &cksum1, &cksum1b); 3945057916 2007-08-01 drh: vfile_aggregate_checksum_disk(vid, &cksum2); 3945057916 2007-08-01 drh: if( blob_compare(&cksum1, &cksum2) ){ 3945057916 2007-08-01 drh: printf("WARNING: manifest checksum does not agree with disk\n"); 3945057916 2007-08-01 drh: } 3945057916 2007-08-01 drh: if( blob_compare(&cksum1, &cksum1b) ){ 3945057916 2007-08-01 drh: printf("WARNING: manifest checksum does not agree with manifest\n"); 3945057916 2007-08-01 drh: } dbda8d6ce9 2007-07-21 drh: db_end_transaction(0); 4452576730 2007-08-11 drh: } 4452576730 2007-08-11 drh: 4452576730 2007-08-11 drh: /* 4452576730 2007-08-11 drh: ** COMMAND: close c9fdb846fb 2007-08-18 drh: ** c9fdb846fb 2007-08-18 drh: ** Usage: %fossil close ?-f|--force? 4452576730 2007-08-11 drh: ** 4452576730 2007-08-11 drh: ** The opposite of "open". Close the current database connection. 4452576730 2007-08-11 drh: ** Require a -f or --force flag if there are unsaved changed in the 4452576730 2007-08-11 drh: ** current check-out. 4452576730 2007-08-11 drh: */ 4452576730 2007-08-11 drh: void close_cmd(void){ 4452576730 2007-08-11 drh: int forceFlag = find_option("force","f",0)!=0; 4452576730 2007-08-11 drh: db_must_be_within_tree(); 4452576730 2007-08-11 drh: if( !forceFlag && unsaved_changes()==1 ){ 4452576730 2007-08-11 drh: fossil_fatal("there are unsaved changes in the current checkout"); 4452576730 2007-08-11 drh: } 4452576730 2007-08-11 drh: db_close(); 4452576730 2007-08-11 drh: unlink(mprintf("%s_FOSSIL_", g.zLocalRoot)); 4452576730 2007-08-11 drh: unlink(mprintf("%s_FOSSIL_-journal", g.zLocalRoot)); dbda8d6ce9 2007-07-21 drh: }