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; dbda8d6ce9 2007-07-21 drh: blob_append(report, zPrefix, nPrefix); dbda8d6ce9 2007-07-21 drh: 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: } 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: ** dbda8d6ce9 2007-07-21 drh: ** Report on the current status of all files. 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 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 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Show all files currently in the repository 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 dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Print a list of all files in the source tree that are not part of dbda8d6ce9 2007-07-21 drh: ** the project 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); dbda8d6ce9 2007-07-21 drh: db_multi_exec("DELETE FROM sfile WHERE x='FOSSIL'"); dbda8d6ce9 2007-07-21 drh: db_prepare(&q, "SELECT x FROM sfile 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)); 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, "# "); dbda8d6ce9 2007-07-21 drh: zEditor = db_global_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); dbda8d6ce9 2007-07-21 drh: zCmd = mprintf("%s %s", zEditor, zFile); 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; dbda8d6ce9 2007-07-21 drh: blob_appendf(pComment, "%b\n", &line); 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; 22552fb803 2007-08-03 dan: memset(&b, 0, sizeof(Blob)); 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; 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: ** dbda8d6ce9 2007-07-21 drh: ** Create a new version containing all of the changes in the current 22552fb803 2007-08-03 dan: ** checkout. A commit is a three step process: 22552fb803 2007-08-03 dan: ** 22552fb803 2007-08-03 dan: ** 1) Add the new content to the blob table, 22552fb803 2007-08-03 dan: ** 2) Create and add the new manifest to the blob table, 22552fb803 2007-08-03 dan: ** 3) Update the vfile table, 22552fb803 2007-08-03 dan: ** 4) Run checks to make sure everything is still internally consistent. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: void commit_cmd(void){ dbda8d6ce9 2007-07-21 drh: int rc; dbda8d6ce9 2007-07-21 drh: int vid, nrid, nvid; dbda8d6ce9 2007-07-21 drh: Blob comment; dbda8d6ce9 2007-07-21 drh: Stmt q; dbda8d6ce9 2007-07-21 drh: Stmt q2; dbda8d6ce9 2007-07-21 drh: char *zUuid, *zDate; dbda8d6ce9 2007-07-21 drh: char *zManifestFile; /* Name of the manifest file */ dbda8d6ce9 2007-07-21 drh: Blob manifest; 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 */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: db_must_be_within_tree(); 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(); 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(); dbda8d6ce9 2007-07-21 drh: if( rc==0 ){ 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); dbda8d6ce9 2007-07-21 drh: vfile_aggregate_checksum_disk(vid, &cksum1); dbda8d6ce9 2007-07-21 drh: prepare_commit_comment(&comment); dbda8d6ce9 2007-07-21 drh: 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); dbda8d6ce9 2007-07-21 drh: nrid = content_put(&content, 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); 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); 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); e37451d9c2 2007-08-01 drh: if( 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); dbda8d6ce9 2007-07-21 drh: nvid = content_put(&manifest, 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: } 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); 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: dbda8d6ce9 2007-07-21 drh: /* Commit */ dbda8d6ce9 2007-07-21 drh: db_end_transaction(0); dbda8d6ce9 2007-07-21 drh: }