Fossil SCM

Add the internal checkin_mtime() function. Use it to implement the --age and -t options to the "fossil ls" command.

drh 2012-10-10 20:03 trunk
Commit 9ba8a393fcc569b2a652984a374adf0870b88af4
+36 -8
--- src/checkin.c
+++ src/checkin.c
@@ -205,46 +205,74 @@
205205
show_common_info(vid, "checkout:", 1, 1);
206206
}
207207
db_record_repository_filename(0);
208208
changes_cmd();
209209
}
210
+
211
+/*
212
+** Implementation of the checkin_mtime SQL function
213
+*/
214
+
210215
211216
/*
212217
** COMMAND: ls
213218
**
214
-** Usage: %fossil ls ?OPTIONS?
219
+** Usage: %fossil ls ?OPTIONS? ?VERSION?
215220
**
216221
** Show the names of all files in the current checkout. The -l provides
217222
** extra information about each file.
218223
**
219224
** Options:
220
-** -l Provide extra information about each file.
225
+** -l Provide extra information about each file.
226
+** --age Show when each file was committed
221227
**
222228
** See also: changes, extra, status
223229
*/
224230
void ls_cmd(void){
225231
int vid;
226232
Stmt q;
227233
int isBrief;
234
+ int showAge;
235
+ char *zOrderBy = "pathname";
228236
229237
isBrief = find_option("l","l", 0)==0;
238
+ showAge = find_option("age",0,0)!=0;
230239
db_must_be_within_tree();
231240
vid = db_lget_int("checkout", 0);
241
+ if( find_option("t","t",0)!=0 ){
242
+ if( showAge ){
243
+ zOrderBy = mprintf("checkin_mtime(%d,rid) DESC", vid);
244
+ }else{
245
+ zOrderBy = "mtime DESC";
246
+ }
247
+ }
248
+ verify_all_options();
232249
vfile_check_signature(vid, 0, 0);
233
- db_prepare(&q,
234
- "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
235
- " FROM vfile"
236
- " ORDER BY 1"
237
- );
250
+ if( showAge ){
251
+ db_prepare(&q,
252
+ "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0),"
253
+ " datetime(checkin_mtime(%d,rid),'unixepoch','localtime')"
254
+ " FROM vfile"
255
+ " ORDER BY %s", vid, zOrderBy
256
+ );
257
+ }else{
258
+ db_prepare(&q,
259
+ "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
260
+ " FROM vfile"
261
+ " ORDER BY %s", zOrderBy
262
+ );
263
+ }
238264
while( db_step(&q)==SQLITE_ROW ){
239265
const char *zPathname = db_column_text(&q,0);
240266
int isDeleted = db_column_int(&q, 1);
241267
int isNew = db_column_int(&q,2)==0;
242268
int chnged = db_column_int(&q,3);
243269
int renamed = db_column_int(&q,4);
244270
char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
245
- if( isBrief ){
271
+ if( showAge ){
272
+ fossil_print("%s %s\n", db_column_text(&q, 5), zPathname);
273
+ }else if( isBrief ){
246274
fossil_print("%s\n", zPathname);
247275
}else if( isNew ){
248276
fossil_print("ADDED %s\n", zPathname);
249277
}else if( isDeleted ){
250278
fossil_print("DELETED %s\n", zPathname);
251279
--- src/checkin.c
+++ src/checkin.c
@@ -205,46 +205,74 @@
205 show_common_info(vid, "checkout:", 1, 1);
206 }
207 db_record_repository_filename(0);
208 changes_cmd();
209 }
 
 
 
 
 
210
211 /*
212 ** COMMAND: ls
213 **
214 ** Usage: %fossil ls ?OPTIONS?
215 **
216 ** Show the names of all files in the current checkout. The -l provides
217 ** extra information about each file.
218 **
219 ** Options:
220 ** -l Provide extra information about each file.
 
221 **
222 ** See also: changes, extra, status
223 */
224 void ls_cmd(void){
225 int vid;
226 Stmt q;
227 int isBrief;
 
 
228
229 isBrief = find_option("l","l", 0)==0;
 
230 db_must_be_within_tree();
231 vid = db_lget_int("checkout", 0);
 
 
 
 
 
 
 
 
232 vfile_check_signature(vid, 0, 0);
233 db_prepare(&q,
234 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
235 " FROM vfile"
236 " ORDER BY 1"
237 );
 
 
 
 
 
 
 
 
 
238 while( db_step(&q)==SQLITE_ROW ){
239 const char *zPathname = db_column_text(&q,0);
240 int isDeleted = db_column_int(&q, 1);
241 int isNew = db_column_int(&q,2)==0;
242 int chnged = db_column_int(&q,3);
243 int renamed = db_column_int(&q,4);
244 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
245 if( isBrief ){
 
 
246 fossil_print("%s\n", zPathname);
247 }else if( isNew ){
248 fossil_print("ADDED %s\n", zPathname);
249 }else if( isDeleted ){
250 fossil_print("DELETED %s\n", zPathname);
251
--- src/checkin.c
+++ src/checkin.c
@@ -205,46 +205,74 @@
205 show_common_info(vid, "checkout:", 1, 1);
206 }
207 db_record_repository_filename(0);
208 changes_cmd();
209 }
210
211 /*
212 ** Implementation of the checkin_mtime SQL function
213 */
214
215
216 /*
217 ** COMMAND: ls
218 **
219 ** Usage: %fossil ls ?OPTIONS? ?VERSION?
220 **
221 ** Show the names of all files in the current checkout. The -l provides
222 ** extra information about each file.
223 **
224 ** Options:
225 ** -l Provide extra information about each file.
226 ** --age Show when each file was committed
227 **
228 ** See also: changes, extra, status
229 */
230 void ls_cmd(void){
231 int vid;
232 Stmt q;
233 int isBrief;
234 int showAge;
235 char *zOrderBy = "pathname";
236
237 isBrief = find_option("l","l", 0)==0;
238 showAge = find_option("age",0,0)!=0;
239 db_must_be_within_tree();
240 vid = db_lget_int("checkout", 0);
241 if( find_option("t","t",0)!=0 ){
242 if( showAge ){
243 zOrderBy = mprintf("checkin_mtime(%d,rid) DESC", vid);
244 }else{
245 zOrderBy = "mtime DESC";
246 }
247 }
248 verify_all_options();
249 vfile_check_signature(vid, 0, 0);
250 if( showAge ){
251 db_prepare(&q,
252 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0),"
253 " datetime(checkin_mtime(%d,rid),'unixepoch','localtime')"
254 " FROM vfile"
255 " ORDER BY %s", vid, zOrderBy
256 );
257 }else{
258 db_prepare(&q,
259 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
260 " FROM vfile"
261 " ORDER BY %s", zOrderBy
262 );
263 }
264 while( db_step(&q)==SQLITE_ROW ){
265 const char *zPathname = db_column_text(&q,0);
266 int isDeleted = db_column_int(&q, 1);
267 int isNew = db_column_int(&q,2)==0;
268 int chnged = db_column_int(&q,3);
269 int renamed = db_column_int(&q,4);
270 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
271 if( showAge ){
272 fossil_print("%s %s\n", db_column_text(&q, 5), zPathname);
273 }else if( isBrief ){
274 fossil_print("%s\n", zPathname);
275 }else if( isNew ){
276 fossil_print("ADDED %s\n", zPathname);
277 }else if( isDeleted ){
278 fossil_print("DELETED %s\n", zPathname);
279
+18
--- src/db.c
+++ src/db.c
@@ -676,10 +676,26 @@
676676
sqlite3_value **argv
677677
){
678678
sqlite3_result_int64(context, time(0));
679679
}
680680
681
+/*
682
+** Function to return the check-in time for a file.
683
+*/
684
+void db_checkin_mtime_function(
685
+ sqlite3_context *context,
686
+ int argc,
687
+ sqlite3_value **argv
688
+){
689
+ i64 mtime;
690
+ int rc = mtime_of_manifest_file(sqlite3_value_int(argv[0]),
691
+ sqlite3_value_int(argv[1]), &mtime);
692
+ if( rc==0 ){
693
+ sqlite3_result_int64(context, mtime);
694
+ }
695
+}
696
+
681697
682698
/*
683699
** Open a database file. Return a pointer to the new database
684700
** connection. An error results in process abort.
685701
*/
@@ -698,10 +714,12 @@
698714
db_err(sqlite3_errmsg(db));
699715
}
700716
sqlite3_busy_timeout(db, 5000);
701717
sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
702718
sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
719
+ sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,
720
+ db_checkin_mtime_function, 0, 0);
703721
return db;
704722
}
705723
706724
707725
/*
708726
--- src/db.c
+++ src/db.c
@@ -676,10 +676,26 @@
676 sqlite3_value **argv
677 ){
678 sqlite3_result_int64(context, time(0));
679 }
680
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
681
682 /*
683 ** Open a database file. Return a pointer to the new database
684 ** connection. An error results in process abort.
685 */
@@ -698,10 +714,12 @@
698 db_err(sqlite3_errmsg(db));
699 }
700 sqlite3_busy_timeout(db, 5000);
701 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
702 sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
 
 
703 return db;
704 }
705
706
707 /*
708
--- src/db.c
+++ src/db.c
@@ -676,10 +676,26 @@
676 sqlite3_value **argv
677 ){
678 sqlite3_result_int64(context, time(0));
679 }
680
681 /*
682 ** Function to return the check-in time for a file.
683 */
684 void db_checkin_mtime_function(
685 sqlite3_context *context,
686 int argc,
687 sqlite3_value **argv
688 ){
689 i64 mtime;
690 int rc = mtime_of_manifest_file(sqlite3_value_int(argv[0]),
691 sqlite3_value_int(argv[1]), &mtime);
692 if( rc==0 ){
693 sqlite3_result_int64(context, mtime);
694 }
695 }
696
697
698 /*
699 ** Open a database file. Return a pointer to the new database
700 ** connection. An error results in process abort.
701 */
@@ -698,10 +714,12 @@
714 db_err(sqlite3_errmsg(db));
715 }
716 sqlite3_busy_timeout(db, 5000);
717 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
718 sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
719 sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,
720 db_checkin_mtime_function, 0, 0);
721 return db;
722 }
723
724
725 /*
726
--- src/descendants.c
+++ src/descendants.c
@@ -156,11 +156,11 @@
156156
157157
/*
158158
** Load the record ID rid and up to N-1 closest ancestors into
159159
** the "ok" table.
160160
*/
161
-void compute_ancestors(int rid, int N){
161
+void compute_ancestors(int rid, int N, int directOnly){
162162
Bag seen;
163163
PQueue queue;
164164
Stmt ins;
165165
Stmt q;
166166
bag_init(&seen);
@@ -168,11 +168,12 @@
168168
bag_insert(&seen, rid);
169169
pqueuex_insert(&queue, rid, 0.0, 0);
170170
db_prepare(&ins, "INSERT OR IGNORE INTO ok VALUES(:rid)");
171171
db_prepare(&q,
172172
"SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid"
173
- " WHERE a.cid=:rid"
173
+ " WHERE a.cid=:rid %s",
174
+ directOnly ? " AND a.isprim" : ""
174175
);
175176
while( (N--)>0 && (rid = pqueuex_extract(&queue, 0))!=0 ){
176177
db_bind_int(&ins, ":rid", rid);
177178
db_step(&ins);
178179
db_reset(&ins);
@@ -202,11 +203,12 @@
202203
void compute_direct_ancestors(int rid, int N){
203204
Stmt ins;
204205
Stmt q;
205206
int gen = 0;
206207
db_multi_exec(
207
- "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER, generation INTEGER PRIMARY KEY);"
208
+ "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER,"
209
+ " generation INTEGER PRIMARY KEY);"
208210
"DELETE FROM ancestor;"
209211
"INSERT INTO ancestor VALUES(%d, 0);", rid
210212
);
211213
db_prepare(&ins, "INSERT INTO ancestor VALUES(:rid, :gen)");
212214
db_prepare(&q,
@@ -225,10 +227,44 @@
225227
db_reset(&ins);
226228
}
227229
db_finalize(&ins);
228230
db_finalize(&q);
229231
}
232
+
233
+/*
234
+** Compute the "mtime" of the file given whose blob.rid is "fid" that
235
+** is part of check-in "vid". The mtime will be the mtime on vid or
236
+** some ancestor of vid where fid first appears.
237
+*/
238
+int mtime_of_manifest_file(
239
+ int vid, /* The check-in that contains fid */
240
+ int fid, /* The id of the file whose check-in time is sought */
241
+ i64 *pMTime /* Write result here */
242
+){
243
+ static int prevVid = -1;
244
+ static Stmt q;
245
+
246
+ if( prevVid!=vid ){
247
+ prevVid = vid;
248
+ db_multi_exec("DROP TABLE IF EXISTS temp.ok;"
249
+ "CREATE TEMP TABLE ok(x INTEGER PRIMARY KEY);");
250
+ compute_ancestors(vid, 100000000, 1);
251
+ }
252
+ db_static_prepare(&q,
253
+ "SELECT (max(event.mtime)-2440587.5)*86400 FROM mlink, event"
254
+ " WHERE mlink.mid=event.objid"
255
+ " AND +mlink.mid IN ok"
256
+ " AND mlink.fid=:fid");
257
+ db_bind_int(&q, ":fid", fid);
258
+ if( db_step(&q)!=SQLITE_ROW ){
259
+ db_reset(&q);
260
+ return 1;
261
+ }
262
+ *pMTime = db_column_int64(&q, 0);
263
+ db_reset(&q);
264
+ return 0;
265
+}
230266
231267
/*
232268
** Load the record ID rid and up to N-1 closest descendants into
233269
** the "ok" table.
234270
*/
235271
--- src/descendants.c
+++ src/descendants.c
@@ -156,11 +156,11 @@
156
157 /*
158 ** Load the record ID rid and up to N-1 closest ancestors into
159 ** the "ok" table.
160 */
161 void compute_ancestors(int rid, int N){
162 Bag seen;
163 PQueue queue;
164 Stmt ins;
165 Stmt q;
166 bag_init(&seen);
@@ -168,11 +168,12 @@
168 bag_insert(&seen, rid);
169 pqueuex_insert(&queue, rid, 0.0, 0);
170 db_prepare(&ins, "INSERT OR IGNORE INTO ok VALUES(:rid)");
171 db_prepare(&q,
172 "SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid"
173 " WHERE a.cid=:rid"
 
174 );
175 while( (N--)>0 && (rid = pqueuex_extract(&queue, 0))!=0 ){
176 db_bind_int(&ins, ":rid", rid);
177 db_step(&ins);
178 db_reset(&ins);
@@ -202,11 +203,12 @@
202 void compute_direct_ancestors(int rid, int N){
203 Stmt ins;
204 Stmt q;
205 int gen = 0;
206 db_multi_exec(
207 "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER, generation INTEGER PRIMARY KEY);"
 
208 "DELETE FROM ancestor;"
209 "INSERT INTO ancestor VALUES(%d, 0);", rid
210 );
211 db_prepare(&ins, "INSERT INTO ancestor VALUES(:rid, :gen)");
212 db_prepare(&q,
@@ -225,10 +227,44 @@
225 db_reset(&ins);
226 }
227 db_finalize(&ins);
228 db_finalize(&q);
229 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
231 /*
232 ** Load the record ID rid and up to N-1 closest descendants into
233 ** the "ok" table.
234 */
235
--- src/descendants.c
+++ src/descendants.c
@@ -156,11 +156,11 @@
156
157 /*
158 ** Load the record ID rid and up to N-1 closest ancestors into
159 ** the "ok" table.
160 */
161 void compute_ancestors(int rid, int N, int directOnly){
162 Bag seen;
163 PQueue queue;
164 Stmt ins;
165 Stmt q;
166 bag_init(&seen);
@@ -168,11 +168,12 @@
168 bag_insert(&seen, rid);
169 pqueuex_insert(&queue, rid, 0.0, 0);
170 db_prepare(&ins, "INSERT OR IGNORE INTO ok VALUES(:rid)");
171 db_prepare(&q,
172 "SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid"
173 " WHERE a.cid=:rid %s",
174 directOnly ? " AND a.isprim" : ""
175 );
176 while( (N--)>0 && (rid = pqueuex_extract(&queue, 0))!=0 ){
177 db_bind_int(&ins, ":rid", rid);
178 db_step(&ins);
179 db_reset(&ins);
@@ -202,11 +203,12 @@
203 void compute_direct_ancestors(int rid, int N){
204 Stmt ins;
205 Stmt q;
206 int gen = 0;
207 db_multi_exec(
208 "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER,"
209 " generation INTEGER PRIMARY KEY);"
210 "DELETE FROM ancestor;"
211 "INSERT INTO ancestor VALUES(%d, 0);", rid
212 );
213 db_prepare(&ins, "INSERT INTO ancestor VALUES(:rid, :gen)");
214 db_prepare(&q,
@@ -225,10 +227,44 @@
227 db_reset(&ins);
228 }
229 db_finalize(&ins);
230 db_finalize(&q);
231 }
232
233 /*
234 ** Compute the "mtime" of the file given whose blob.rid is "fid" that
235 ** is part of check-in "vid". The mtime will be the mtime on vid or
236 ** some ancestor of vid where fid first appears.
237 */
238 int mtime_of_manifest_file(
239 int vid, /* The check-in that contains fid */
240 int fid, /* The id of the file whose check-in time is sought */
241 i64 *pMTime /* Write result here */
242 ){
243 static int prevVid = -1;
244 static Stmt q;
245
246 if( prevVid!=vid ){
247 prevVid = vid;
248 db_multi_exec("DROP TABLE IF EXISTS temp.ok;"
249 "CREATE TEMP TABLE ok(x INTEGER PRIMARY KEY);");
250 compute_ancestors(vid, 100000000, 1);
251 }
252 db_static_prepare(&q,
253 "SELECT (max(event.mtime)-2440587.5)*86400 FROM mlink, event"
254 " WHERE mlink.mid=event.objid"
255 " AND +mlink.mid IN ok"
256 " AND mlink.fid=:fid");
257 db_bind_int(&q, ":fid", fid);
258 if( db_step(&q)!=SQLITE_ROW ){
259 db_reset(&q);
260 return 1;
261 }
262 *pMTime = db_column_int64(&q, 0);
263 db_reset(&q);
264 return 0;
265 }
266
267 /*
268 ** Load the record ID rid and up to N-1 closest descendants into
269 ** the "ok" table.
270 */
271
+2 -2
--- src/timeline.c
+++ src/timeline.c
@@ -1023,11 +1023,11 @@
10231023
if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s");
10241024
if( useDividers ) timeline_add_dividers(0, d_rid);
10251025
db_multi_exec("DELETE FROM ok");
10261026
}
10271027
if( p_rid ){
1028
- compute_ancestors(p_rid, nEntry+1);
1028
+ compute_ancestors(p_rid, nEntry+1, 0);
10291029
np = db_int(0, "SELECT count(*)-1 FROM ok");
10301030
if( np>0 ){
10311031
if( nd>0 ) blob_appendf(&desc, " and ");
10321032
blob_appendf(&desc, "%d ancestors", np);
10331033
db_multi_exec("%s", blob_str(&sql));
@@ -1538,11 +1538,11 @@
15381538
if( mode==3 || mode==4 ){
15391539
db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
15401540
if( mode==3 ){
15411541
compute_descendants(objid, n);
15421542
}else{
1543
- compute_ancestors(objid, n);
1543
+ compute_ancestors(objid, n, 0);
15441544
}
15451545
blob_appendf(&sql, " AND blob.rid IN ok");
15461546
}
15471547
if( zType && (zType[0]!='a') ){
15481548
blob_appendf(&sql, " AND event.type=%Q ", zType);
15491549
--- src/timeline.c
+++ src/timeline.c
@@ -1023,11 +1023,11 @@
1023 if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s");
1024 if( useDividers ) timeline_add_dividers(0, d_rid);
1025 db_multi_exec("DELETE FROM ok");
1026 }
1027 if( p_rid ){
1028 compute_ancestors(p_rid, nEntry+1);
1029 np = db_int(0, "SELECT count(*)-1 FROM ok");
1030 if( np>0 ){
1031 if( nd>0 ) blob_appendf(&desc, " and ");
1032 blob_appendf(&desc, "%d ancestors", np);
1033 db_multi_exec("%s", blob_str(&sql));
@@ -1538,11 +1538,11 @@
1538 if( mode==3 || mode==4 ){
1539 db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
1540 if( mode==3 ){
1541 compute_descendants(objid, n);
1542 }else{
1543 compute_ancestors(objid, n);
1544 }
1545 blob_appendf(&sql, " AND blob.rid IN ok");
1546 }
1547 if( zType && (zType[0]!='a') ){
1548 blob_appendf(&sql, " AND event.type=%Q ", zType);
1549
--- src/timeline.c
+++ src/timeline.c
@@ -1023,11 +1023,11 @@
1023 if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s");
1024 if( useDividers ) timeline_add_dividers(0, d_rid);
1025 db_multi_exec("DELETE FROM ok");
1026 }
1027 if( p_rid ){
1028 compute_ancestors(p_rid, nEntry+1, 0);
1029 np = db_int(0, "SELECT count(*)-1 FROM ok");
1030 if( np>0 ){
1031 if( nd>0 ) blob_appendf(&desc, " and ");
1032 blob_appendf(&desc, "%d ancestors", np);
1033 db_multi_exec("%s", blob_str(&sql));
@@ -1538,11 +1538,11 @@
1538 if( mode==3 || mode==4 ){
1539 db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
1540 if( mode==3 ){
1541 compute_descendants(objid, n);
1542 }else{
1543 compute_ancestors(objid, n, 0);
1544 }
1545 blob_appendf(&sql, " AND blob.rid IN ok");
1546 }
1547 if( zType && (zType[0]!='a') ){
1548 blob_appendf(&sql, " AND event.type=%Q ", zType);
1549

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button