8c8f8616a6 2009-10-31 drh: /* 8c8f8616a6 2009-10-31 drh: ** Copyright (c) 2009 D. Richard Hipp 8c8f8616a6 2009-10-31 drh: ** 8c8f8616a6 2009-10-31 drh: ** This program is free software; you can redistribute it and/or 8c8f8616a6 2009-10-31 drh: ** modify it under the terms of the GNU General Public 8c8f8616a6 2009-10-31 drh: ** License version 2 as published by the Free Software Foundation. 8c8f8616a6 2009-10-31 drh: ** 8c8f8616a6 2009-10-31 drh: ** This program is distributed in the hope that it will be useful, 8c8f8616a6 2009-10-31 drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of 8c8f8616a6 2009-10-31 drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 8c8f8616a6 2009-10-31 drh: ** General Public License for more details. 8c8f8616a6 2009-10-31 drh: ** 8c8f8616a6 2009-10-31 drh: ** You should have received a copy of the GNU General Public 8c8f8616a6 2009-10-31 drh: ** License along with this library; if not, write to the 8c8f8616a6 2009-10-31 drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, 8c8f8616a6 2009-10-31 drh: ** Boston, MA 02111-1307, USA. 8c8f8616a6 2009-10-31 drh: ** 8c8f8616a6 2009-10-31 drh: ** Author contact information: 8c8f8616a6 2009-10-31 drh: ** drh@hwaci.com 8c8f8616a6 2009-10-31 drh: ** http://www.hwaci.com/drh/ 8c8f8616a6 2009-10-31 drh: ** 8c8f8616a6 2009-10-31 drh: ******************************************************************************* 8c8f8616a6 2009-10-31 drh: ** 8c8f8616a6 2009-10-31 drh: ** This file contains code to implement the "finfo" command. 8c8f8616a6 2009-10-31 drh: */ 8c8f8616a6 2009-10-31 drh: #include "config.h" 8c8f8616a6 2009-10-31 drh: #include "finfo.h" 8c8f8616a6 2009-10-31 drh: 8c8f8616a6 2009-10-31 drh: /* 8c8f8616a6 2009-10-31 drh: ** COMMAND: finfo 8c8f8616a6 2009-10-31 drh: ** 8c8f8616a6 2009-10-31 drh: ** Usage: %fossil finfo FILENAME 8c8f8616a6 2009-10-31 drh: ** 8c8f8616a6 2009-10-31 drh: ** Print the change history for a single file. 8c8f8616a6 2009-10-31 drh: ** 8c8f8616a6 2009-10-31 drh: ** The "--limit N" and "--offset P" options limits the output to the first 8c8f8616a6 2009-10-31 drh: ** N changes after skipping P changes. 8c8f8616a6 2009-10-31 drh: */ 8c8f8616a6 2009-10-31 drh: void finfo_cmd(void){ 8c8f8616a6 2009-10-31 drh: Stmt q; 8c8f8616a6 2009-10-31 drh: int vid; 8c8f8616a6 2009-10-31 drh: Blob dest; 8c8f8616a6 2009-10-31 drh: const char *zFilename; 8c8f8616a6 2009-10-31 drh: const char *zLimit; 8c8f8616a6 2009-10-31 drh: const char *zOffset; 8c8f8616a6 2009-10-31 drh: int iLimit, iOffset; 8c8f8616a6 2009-10-31 drh: 8c8f8616a6 2009-10-31 drh: db_must_be_within_tree(); 8c8f8616a6 2009-10-31 drh: vid = db_lget_int("checkout", 0); 8c8f8616a6 2009-10-31 drh: if( vid==0 ){ 8c8f8616a6 2009-10-31 drh: fossil_panic("no checkout to finfo files in"); 8c8f8616a6 2009-10-31 drh: } 8c8f8616a6 2009-10-31 drh: zLimit = find_option("limit",0,1); 8c8f8616a6 2009-10-31 drh: iLimit = zLimit ? atoi(zLimit) : -1; 8c8f8616a6 2009-10-31 drh: zOffset = find_option("offset",0,1); 8c8f8616a6 2009-10-31 drh: iOffset = zOffset ? atoi(zOffset) : 0; 8c8f8616a6 2009-10-31 drh: if (g.argc<3) { 8c8f8616a6 2009-10-31 drh: usage("FILENAME"); 8c8f8616a6 2009-10-31 drh: } 8c8f8616a6 2009-10-31 drh: file_tree_name(g.argv[2], &dest, 1); 8c8f8616a6 2009-10-31 drh: zFilename = blob_str(&dest); 8c8f8616a6 2009-10-31 drh: db_prepare(&q, 8c8f8616a6 2009-10-31 drh: "SELECT b.uuid, ci.uuid, date(event.mtime,'localtime')," 8c8f8616a6 2009-10-31 drh: " coalesce(event.ecomment, event.comment)," 8c8f8616a6 2009-10-31 drh: " coalesce(event.euser, event.user)" 8c8f8616a6 2009-10-31 drh: " FROM mlink, blob b, event, blob ci" 8c8f8616a6 2009-10-31 drh: " WHERE mlink.fnid=(SELECT fnid FROM filename WHERE name=%Q)" 8c8f8616a6 2009-10-31 drh: " AND b.rid=mlink.fid" 8c8f8616a6 2009-10-31 drh: " AND event.objid=mlink.mid" 8c8f8616a6 2009-10-31 drh: " AND event.objid=ci.rid" 8c8f8616a6 2009-10-31 drh: " ORDER BY event.mtime DESC LIMIT %d OFFSET %d", 8c8f8616a6 2009-10-31 drh: zFilename, iLimit, iOffset 8c8f8616a6 2009-10-31 drh: ); 8c8f8616a6 2009-10-31 drh: 8c8f8616a6 2009-10-31 drh: printf("History of %s\n", zFilename); 8c8f8616a6 2009-10-31 drh: while( db_step(&q)==SQLITE_ROW ){ 8c8f8616a6 2009-10-31 drh: const char *zFileUuid = db_column_text(&q, 0); 8c8f8616a6 2009-10-31 drh: const char *zCiUuid = db_column_text(&q, 1); 8c8f8616a6 2009-10-31 drh: const char *zDate = db_column_text(&q, 2); 8c8f8616a6 2009-10-31 drh: const char *zCom = db_column_text(&q, 3); 8c8f8616a6 2009-10-31 drh: const char *zUser = db_column_text(&q, 4); 8c8f8616a6 2009-10-31 drh: char *zOut; 8c8f8616a6 2009-10-31 drh: printf("%s ", zDate); 8c8f8616a6 2009-10-31 drh: zOut = sqlite3_mprintf("[%.10s] %s (user: %s, artifact: [%.10s])", 8c8f8616a6 2009-10-31 drh: zCiUuid, zCom, zUser, zFileUuid); 8c8f8616a6 2009-10-31 drh: comment_print(zOut, 11, 79); 8c8f8616a6 2009-10-31 drh: sqlite3_free(zOut); 8c8f8616a6 2009-10-31 drh: } 8c8f8616a6 2009-10-31 drh: db_finalize(&q); 8c8f8616a6 2009-10-31 drh: blob_reset(&dest); 8c8f8616a6 2009-10-31 drh: } 8c8f8616a6 2009-10-31 drh: 8c8f8616a6 2009-10-31 drh: 8c8f8616a6 2009-10-31 drh: /* 8c8f8616a6 2009-10-31 drh: ** WEBPAGE: finfo 8c8f8616a6 2009-10-31 drh: ** URL: /finfo?name=FILENAME 8c8f8616a6 2009-10-31 drh: ** 8c8f8616a6 2009-10-31 drh: ** Show the complete change history for a single file. 8c8f8616a6 2009-10-31 drh: */ 8c8f8616a6 2009-10-31 drh: void finfo_page(void){ 8c8f8616a6 2009-10-31 drh: Stmt q; 8c8f8616a6 2009-10-31 drh: const char *zFilename; 8c8f8616a6 2009-10-31 drh: char zPrevDate[20]; 8c8f8616a6 2009-10-31 drh: Blob title; 8c8f8616a6 2009-10-31 drh: 8c8f8616a6 2009-10-31 drh: login_check_credentials(); 8c8f8616a6 2009-10-31 drh: if( !g.okRead ){ login_needed(); return; } 8c8f8616a6 2009-10-31 drh: style_header("File History"); 8c8f8616a6 2009-10-31 drh: login_anonymous_available(); 8c8f8616a6 2009-10-31 drh: 8c8f8616a6 2009-10-31 drh: zPrevDate[0] = 0; 8c8f8616a6 2009-10-31 drh: zFilename = PD("name",""); 8c8f8616a6 2009-10-31 drh: db_prepare(&q, 8c8f8616a6 2009-10-31 drh: "SELECT substr(b.uuid,1,10), datetime(event.mtime,'localtime')," 8c8f8616a6 2009-10-31 drh: " coalesce(event.ecomment, event.comment)," 8c8f8616a6 2009-10-31 drh: " coalesce(event.euser, event.user)," 8c8f8616a6 2009-10-31 drh: " mlink.pid, mlink.fid, mlink.mid, mlink.fnid, ci.uuid" 8c8f8616a6 2009-10-31 drh: " FROM mlink, blob b, event, blob ci" 8c8f8616a6 2009-10-31 drh: " WHERE mlink.fnid=(SELECT fnid FROM filename WHERE name=%Q)" 8c8f8616a6 2009-10-31 drh: " AND b.rid=mlink.fid" 8c8f8616a6 2009-10-31 drh: " AND event.objid=mlink.mid" 8c8f8616a6 2009-10-31 drh: " AND event.objid=ci.rid" 8c8f8616a6 2009-10-31 drh: " ORDER BY event.mtime DESC", 8c8f8616a6 2009-10-31 drh: zFilename 8c8f8616a6 2009-10-31 drh: ); 8c8f8616a6 2009-10-31 drh: blob_zero(&title); 8c8f8616a6 2009-10-31 drh: blob_appendf(&title, "History of "); 8c8f8616a6 2009-10-31 drh: hyperlinked_path(zFilename, &title); 8c8f8616a6 2009-10-31 drh: @ <h2>%b(&title)</h2> 8c8f8616a6 2009-10-31 drh: blob_reset(&title); 8c8f8616a6 2009-10-31 drh: @ <table cellspacing=0 border=0 cellpadding=0> 8c8f8616a6 2009-10-31 drh: while( db_step(&q)==SQLITE_ROW ){ 8c8f8616a6 2009-10-31 drh: const char *zUuid = db_column_text(&q, 0); 8c8f8616a6 2009-10-31 drh: const char *zDate = db_column_text(&q, 1); 8c8f8616a6 2009-10-31 drh: const char *zCom = db_column_text(&q, 2); 8c8f8616a6 2009-10-31 drh: const char *zUser = db_column_text(&q, 3); 8c8f8616a6 2009-10-31 drh: int fpid = db_column_int(&q, 4); 8c8f8616a6 2009-10-31 drh: int frid = db_column_int(&q, 5); 8c8f8616a6 2009-10-31 drh: int mid = db_column_int(&q, 6); 8c8f8616a6 2009-10-31 drh: int fnid = db_column_int(&q, 7); 8c8f8616a6 2009-10-31 drh: const char *zCkin = db_column_text(&q,8); 8c8f8616a6 2009-10-31 drh: char zShort[20]; 8c8f8616a6 2009-10-31 drh: char zShortCkin[20]; 8c8f8616a6 2009-10-31 drh: if( memcmp(zDate, zPrevDate, 10) ){ 8c8f8616a6 2009-10-31 drh: sprintf(zPrevDate, "%.10s", zDate); 8c8f8616a6 2009-10-31 drh: @ <tr><td colspan=3> 8c8f8616a6 2009-10-31 drh: @ <div class="divider">%s(zPrevDate)</div> 8c8f8616a6 2009-10-31 drh: @ </td></tr> 8c8f8616a6 2009-10-31 drh: } 8c8f8616a6 2009-10-31 drh: @ <tr><td valign="top">%s(&zDate[11])</td> 8c8f8616a6 2009-10-31 drh: @ <td width="20"></td> 8c8f8616a6 2009-10-31 drh: @ <td valign="top" align="left"> 8c8f8616a6 2009-10-31 drh: sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zUuid); 8c8f8616a6 2009-10-31 drh: sqlite3_snprintf(sizeof(zShortCkin), zShortCkin, "%.10s", zCkin); 8c8f8616a6 2009-10-31 drh: if( g.okHistory ){ 8c8f8616a6 2009-10-31 drh: @ <a href="%s(g.zTop)/artifact/%s(zUuid)">[%s(zShort)]</a> 8c8f8616a6 2009-10-31 drh: }else{ 8c8f8616a6 2009-10-31 drh: @ [%s(zShort)] 8c8f8616a6 2009-10-31 drh: } 8c8f8616a6 2009-10-31 drh: @ part of check-in 8c8f8616a6 2009-10-31 drh: hyperlink_to_uuid(zShortCkin); 8c8f8616a6 2009-10-31 drh: @ %h(zCom) (By: 8c8f8616a6 2009-10-31 drh: hyperlink_to_user(zUser, zDate, " on"); 8c8f8616a6 2009-10-31 drh: hyperlink_to_date(zDate, ")"); 8c8f8616a6 2009-10-31 drh: if( g.okHistory ){ 8c8f8616a6 2009-10-31 drh: if( fpid ){ 8c8f8616a6 2009-10-31 drh: @ <a href="%s(g.zBaseURL)/fdiff?v1=%d(fpid)&v2=%d(frid)">[diff]</a> 8c8f8616a6 2009-10-31 drh: } 8c8f8616a6 2009-10-31 drh: @ <a href="%s(g.zBaseURL)/annotate?mid=%d(mid)&fnid=%d(fnid)"> 8c8f8616a6 2009-10-31 drh: @ [annotate]</a> 8c8f8616a6 2009-10-31 drh: @ </td> 8c8f8616a6 2009-10-31 drh: } 8c8f8616a6 2009-10-31 drh: } 8c8f8616a6 2009-10-31 drh: db_finalize(&q); 8c8f8616a6 2009-10-31 drh: @ </table> 8c8f8616a6 2009-10-31 drh: style_footer(); 8c8f8616a6 2009-10-31 drh: }