Fossil

Check-in [3945057916]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add primitive start-time and duration controols to the timeline. Additional checksums on check-in and check-out.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 394505791628e571d7020d6cdd85235ec847f49d
User & Date: drh 2007-08-01 21:03:03.000
Context
2007-08-01
21:59
Add the ability to sign manifests using GPG during a check-in. Due to a bug in the manifest parser, older versions will not be able to check-out signed manifests. ... (check-in: e37451d9c2 user: drh tags: trunk)
21:03
Add primitive start-time and duration controols to the timeline. Additional checksums on check-in and check-out. ... (check-in: 3945057916 user: drh tags: trunk)
20:05
Documentation updates. Added Makefile. ... (check-in: 0e265b0184 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/checkin.c.
225
226
227
228
229
230
231

232
233
234
235
236
237
238
  Stmt q;
  Stmt q2;
  char *zUuid, *zDate;
  char *zManifestFile;   /* Name of the manifest file */
  Blob manifest;
  Blob mcksum;           /* Self-checksum on the manifest */
  Blob cksum1, cksum2;   /* Before and after commit checksums */

  
  db_must_be_within_tree();
  user_select();
  db_begin_transaction();
  rc = unsaved_changes();
  if( rc==0 ){
    fossil_panic("nothing has changed");







>







225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
  Stmt q;
  Stmt q2;
  char *zUuid, *zDate;
  char *zManifestFile;   /* Name of the manifest file */
  Blob manifest;
  Blob mcksum;           /* Self-checksum on the manifest */
  Blob cksum1, cksum2;   /* Before and after commit checksums */
  Blob cksum1b;          /* Checksum recorded in the manifest */
  
  db_must_be_within_tree();
  user_select();
  db_begin_transaction();
  rc = unsaved_changes();
  if( rc==0 ){
    fossil_panic("nothing has changed");
320
321
322
323
324
325
326
327




328
329

330
331
332
333
334
335
336
337
338
  db_lset_int("checkout", nvid);

  /* Verify that the tree checksum is unchanged */
  vfile_aggregate_checksum_repository(nvid, &cksum2);
  if( blob_compare(&cksum1, &cksum2) ){
    fossil_panic("tree checksum does not match repository after commit");
  }
  vfile_aggregate_checksum_manifest(nvid, &cksum2);




  if( blob_compare(&cksum1, &cksum2) ){
    fossil_panic("tree checksum does not match manifest after commit");

  }
  vfile_aggregate_checksum_disk(nvid, &cksum2);
  if( blob_compare(&cksum1, &cksum2) ){
    fossil_panic("tree checksums before and after commit do not match");
  }

  /* Commit */
  db_end_transaction(0);  
}







|
>
>
>
>

|
>









321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
  db_lset_int("checkout", nvid);

  /* Verify that the tree checksum is unchanged */
  vfile_aggregate_checksum_repository(nvid, &cksum2);
  if( blob_compare(&cksum1, &cksum2) ){
    fossil_panic("tree checksum does not match repository after commit");
  }
  vfile_aggregate_checksum_manifest(nvid, &cksum2, &cksum1b);
  if( blob_compare(&cksum1, &cksum1b) ){
    fossil_panic("manifest checksum does not agree with manifest: "
                 "%b versus %b", &cksum1, &cksum1b);
  }
  if( blob_compare(&cksum1, &cksum2) ){
    fossil_panic("tree checksum does not match manifest after commit: "
                 "%b versus %b", &cksum1, &cksum2);
  }
  vfile_aggregate_checksum_disk(nvid, &cksum2);
  if( blob_compare(&cksum1, &cksum2) ){
    fossil_panic("tree checksums before and after commit do not match");
  }

  /* Commit */
  db_end_transaction(0);  
}
Changes to src/checkout.c.
97
98
99
100
101
102
103

104
105
106
107
108
109
110
**
** Check out a version specified on the command-line.
*/
void checkout_cmd(void){
  int forceFlag;
  int noWrite;
  int vid, prior;

  
  db_must_be_within_tree();
  db_begin_transaction();
  forceFlag = find_option("force","f",0)!=0;
  noWrite = find_option("dontwrite",0,0)!=0;
  if( g.argc!=3 ) usage("?--force? VERSION");
  if( !forceFlag && unsaved_changes()==1 ){







>







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
**
** Check out a version specified on the command-line.
*/
void checkout_cmd(void){
  int forceFlag;
  int noWrite;
  int vid, prior;
  Blob cksum1, cksum1b, cksum2;
  
  db_must_be_within_tree();
  db_begin_transaction();
  forceFlag = find_option("force","f",0)!=0;
  noWrite = find_option("dontwrite",0,0)!=0;
  if( g.argc!=3 ) usage("?--force? VERSION");
  if( !forceFlag && unsaved_changes()==1 ){
132
133
134
135
136
137
138








139
140
    zManFile = mprintf("%smanifest", g.zLocalRoot);
    content_get(vid, &manifest);
    blob_write_to_file(&manifest, zManFile);
    free(zManFile);
    db_lset_int("checkout", vid);
  }
  db_multi_exec("DELETE FROM vmerge");








  db_end_transaction(0);
}







>
>
>
>
>
>
>
>


133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
    zManFile = mprintf("%smanifest", g.zLocalRoot);
    content_get(vid, &manifest);
    blob_write_to_file(&manifest, zManFile);
    free(zManFile);
    db_lset_int("checkout", vid);
  }
  db_multi_exec("DELETE FROM vmerge");
  vfile_aggregate_checksum_manifest(vid, &cksum1, &cksum1b);
  vfile_aggregate_checksum_disk(vid, &cksum2);
  if( blob_compare(&cksum1, &cksum2) ){
    printf("WARNING: manifest checksum does not agree with disk\n");
  }
  if( blob_compare(&cksum1, &cksum1b) ){
    printf("WARNING: manifest checksum does not agree with manifest\n");
  }
  db_end_transaction(0);
}
Changes to src/descendents.c.
138
139
140
141
142
143
144
145
146
147
148
    "       event.comment, event.user"
    "  FROM blob, event"
    " WHERE blob.rid IN"
    "       (SELECT cid FROM plink EXCEPT SELECT pid FROM plink)"
    "   AND event.objid=blob.rid"
    " ORDER BY event.mtime DESC"
  );
  www_print_timeline(&q);
  db_finalize(&q);
  style_footer();
}







|



138
139
140
141
142
143
144
145
146
147
148
    "       event.comment, event.user"
    "  FROM blob, event"
    " WHERE blob.rid IN"
    "       (SELECT cid FROM plink EXCEPT SELECT pid FROM plink)"
    "   AND event.objid=blob.rid"
    " ORDER BY event.mtime DESC"
  );
  www_print_timeline(&q, 0);
  db_finalize(&q);
  style_footer();
}
Changes to src/timeline.c.
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
** should return 4 columns:
**
**    0.  UUID
**    1.  Date/Time
**    2.  Comment string
**    3.  User
*/
void www_print_timeline(Stmt *pQuery){
  char zPrevDate[20];
  zPrevDate[0] = 0;
  @ <table cellspacing=0 border=0 cellpadding=0>
  while( db_step(pQuery)==SQLITE_ROW ){
    const char *zDate = db_column_text(pQuery, 1);
    if( memcmp(zDate, zPrevDate, 10) ){
      sprintf(zPrevDate, "%.10s", zDate);







|







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
** should return 4 columns:
**
**    0.  UUID
**    1.  Date/Time
**    2.  Comment string
**    3.  User
*/
void www_print_timeline(Stmt *pQuery, char *zLastDate){
  char zPrevDate[20];
  zPrevDate[0] = 0;
  @ <table cellspacing=0 border=0 cellpadding=0>
  while( db_step(pQuery)==SQLITE_ROW ){
    const char *zDate = db_column_text(pQuery, 1);
    if( memcmp(zDate, zPrevDate, 10) ){
      sprintf(zPrevDate, "%.10s", zDate);
80
81
82
83
84
85
86



87
88
89
90
91
92
93
94
95
96
97




98
99
100
101
102
103
104







105
106
107
108
109
110










111
112
















113
114

115
116
117
118
119
120
121
      @ </td></tr>
    }
    @ <tr><td valign="top">%s(&zDate[11])</td>
    @ <td width="20"></td>
    @ <td valign="top" align="left">
    hyperlink_to_uuid(db_column_text(pQuery,0));
    @ %h(db_column_text(pQuery,2)) (by %h(db_column_text(pQuery,3)))</td>



  }
  @ </table>
}



/*
** WEBPAGE: timeline
*/
void page_timeline(void){
  Stmt q;





  /* To view the timeline, must have permission to read project data.
  */
  login_check_credentials();
  if( !g.okRead ){ login_needed(); return; }

  style_header("Timeline");







  db_prepare(&q,
    "SELECT uuid, datetime(event.mtime,'localtime'), comment, user"
    "  FROM event, blob"
    " WHERE event.type='ci' AND blob.rid=event.objid"
    " ORDER BY event.mtime DESC"
  );










  www_print_timeline(&q);
  db_finalize(&q);
















  style_footer();
}

/*
** The input query q selects various records.  Print a human-readable
** summary of those records.
**
** Limit the number of entries printed to nLine.
*/
void print_timeline(Stmt *q, int mxLine){







>
>
>











>
>
>
>







>
>
>
>
>
>
>
|



<

>
>
>
>
>
>
>
>
>
>
|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122

123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
      @ </td></tr>
    }
    @ <tr><td valign="top">%s(&zDate[11])</td>
    @ <td width="20"></td>
    @ <td valign="top" align="left">
    hyperlink_to_uuid(db_column_text(pQuery,0));
    @ %h(db_column_text(pQuery,2)) (by %h(db_column_text(pQuery,3)))</td>
    if( zLastDate ){
      strcpy(zLastDate, zDate);
    }
  }
  @ </table>
}



/*
** WEBPAGE: timeline
*/
void page_timeline(void){
  Stmt q;
  char *zSQL;
  char zDate[100];
  const char *zStart = P("d");
  int nEntry = atoi(PD("n","25"));

  /* To view the timeline, must have permission to read project data.
  */
  login_check_credentials();
  if( !g.okRead ){ login_needed(); return; }

  style_header("Timeline");
  if( !g.okHistory &&
      db_exists("SELECT 1 FROM user"
                " WHERE login='anonymous'"
                "   AND cap LIKE '%%h%%'") ){
    @ <p><b>Note:</b> You will be able to see much more timeline
    @ information if <a href="%s(g.zBaseURL)/login">login</a>.</p>
  }
  zSQL = mprintf(
    "SELECT uuid, datetime(event.mtime,'localtime'), comment, user"
    "  FROM event, blob"
    " WHERE event.type='ci' AND blob.rid=event.objid"

  );
  if( zStart ){
    while( isspace(zStart[0]) ){ zStart++; }
    if( zStart[0] ){
      zSQL = mprintf("%z AND event.mtime<=julianday(%Q, 'localtime')",
                      zSQL, zStart);
    }
  }
  zSQL = mprintf("%z ORDER BY event.mtime DESC LIMIT %d", zSQL, nEntry);
  db_prepare(&q, zSQL);
  free(zSQL);
  www_print_timeline(&q, zDate);
  db_finalize(&q);
  if( zStart==0 ){
    zStart = zDate;
  }
  @ <hr>
  @ <form method="GET" action="%s(g.zBaseURL)/timeline">
  @ Start Date:
  @ <input type="text" size="30" value="%h(zStart)" name="d">
  @ Number Of Entries:  
  @ <input type="text" size="4" value="%d(nEntry)" name="n">
  @ <br><input type="submit" value="Submit">
  @ </form>
  @ <form method="GET" action="%s(g.zBaseURL)/timeline">
  @ <input type="hidden" value="%h(zDate)" name="d">
  @ <input type="hidden" value="%d(nEntry)" name="n">
  @ <input type="submit" value="Next %d(nEntry) Rows">
  @ </form>
  style_footer();
}

/*
** The input query q selects various records.  Print a human-readable
** summary of those records.
**
** Limit the number of entries printed to nLine.
*/
void print_timeline(Stmt *q, int mxLine){
Changes to src/vfile.c.
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355




356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375

376

/*
** Compute an aggregate MD5 checksum over the repository image of every
** file in manifest vid.  The file names are part of the checksum.
**
** Return the resulting checksum in blob pOut.
*/
void vfile_aggregate_checksum_manifest(int vid, Blob *pOut){
  int i, fid;
  Blob file, mfile;
  Manifest m;
  char zBuf[100];

  db_must_be_within_tree();
  content_get(vid, &mfile);
  if( manifest_parse(&m, &mfile)==0 ){
    blob_zero(pOut);
    return;
  }
  for(i=0; i<m.nFile; i++){
    fid = uuid_to_rid(m.aFile[i].zUuid, 0);
    md5sum_step_text(m.aFile[i].zName, -1);
    content_get(fid, &file);
    sprintf(zBuf, " %d\n", blob_size(&file));
    md5sum_step_text(zBuf, -1);
    md5sum_step_blob(&file);
    blob_reset(&file);
  }




  manifest_clear(&m);
  md5sum_finish(pOut);
}

/*
** COMMAND: test-agg-cksum
*/
void test_agg_cksum_cmd(void){
  int vid;
  Blob hash;
  db_must_be_within_tree();
  vid = db_lget_int("checkout", 0);
  vfile_aggregate_checksum_disk(vid, &hash);
  printf("disk:     %s\n", blob_str(&hash));
  blob_reset(&hash);
  vfile_aggregate_checksum_repository(vid, &hash);
  printf("archive:  %s\n", blob_str(&hash));
  blob_reset(&hash);
  vfile_aggregate_checksum_manifest(vid, &hash);
  printf("manifest: %s\n", blob_str(&hash));

}







|




















>
>
>
>









|








|

>

328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381

/*
** Compute an aggregate MD5 checksum over the repository image of every
** file in manifest vid.  The file names are part of the checksum.
**
** Return the resulting checksum in blob pOut.
*/
void vfile_aggregate_checksum_manifest(int vid, Blob *pOut, Blob *pManOut){
  int i, fid;
  Blob file, mfile;
  Manifest m;
  char zBuf[100];

  db_must_be_within_tree();
  content_get(vid, &mfile);
  if( manifest_parse(&m, &mfile)==0 ){
    blob_zero(pOut);
    return;
  }
  for(i=0; i<m.nFile; i++){
    fid = uuid_to_rid(m.aFile[i].zUuid, 0);
    md5sum_step_text(m.aFile[i].zName, -1);
    content_get(fid, &file);
    sprintf(zBuf, " %d\n", blob_size(&file));
    md5sum_step_text(zBuf, -1);
    md5sum_step_blob(&file);
    blob_reset(&file);
  }
  if( pManOut ){
    blob_zero(pManOut);
    blob_append(pManOut, m.zRepoCksum, -1);
  }
  manifest_clear(&m);
  md5sum_finish(pOut);
}

/*
** COMMAND: test-agg-cksum
*/
void test_agg_cksum_cmd(void){
  int vid;
  Blob hash, hash2;
  db_must_be_within_tree();
  vid = db_lget_int("checkout", 0);
  vfile_aggregate_checksum_disk(vid, &hash);
  printf("disk:     %s\n", blob_str(&hash));
  blob_reset(&hash);
  vfile_aggregate_checksum_repository(vid, &hash);
  printf("archive:  %s\n", blob_str(&hash));
  blob_reset(&hash);
  vfile_aggregate_checksum_manifest(vid, &hash, &hash2);
  printf("manifest: %s\n", blob_str(&hash));
  printf("recorded: %s\n", blob_str(&hash2));
}