Check-in [923d644b89]
Not logged in
Overview

SHA1 Hash:923d644b89211895883a8442883afed8ee02a6e9
Date: 2009-01-28 21:41:41
User: drh
Comment:Add the ci=LABEL parameter to the "dir" webpage in order to look at just files within a single check-in. Add a Download link on the artifact and hexdump viewers.
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified src/browse.c from [9050864c16] to [b26f9d5a29].

@@ -101,18 +101,24 @@
 ** WEBPAGE: dir
 **
 ** Query parameters:
 **
 **    name=PATH        Directory to display.  Required.
+**    ci=LABEL         Show only files in this check-in.  Optional.
 */
 void page_dir(void){
   const char *zD = P("name");
   int mxLen;
   int nCol, nRow;
   int cnt, i;
   char *zPrefix;
   Stmt q;
+  const char *zCI = P("ci");
+  int rid = 0;
+  Blob content;
+  Manifest m;
+  const char *zSubdirLink;
 
   login_check_credentials();
   if( !g.okHistory ){ login_needed(); return; }
   style_header("File List");
   sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
@@ -119,45 +125,84 @@
                           pathelementFunc, 0, 0);
 
   /* If the name= parameter is an empty string, make it a NULL pointer */
   if( zD && strlen(zD)==0 ){ zD = 0; }
 
+  /* If a specific check-in is requested, fetch and parse it. */
+  if( zCI && (rid = name_to_rid(zCI))!=0 && content_get(rid, &content) ){
+    if( !manifest_parse(&m, &content) || m.type!=CFTYPE_MANIFEST ){
+      zCI = 0;
+    }
+  }
+
   /* Compute the title of the page */
   if( zD ){
     Blob title;
 
     blob_zero(&title);
     blob_appendf(&title, "Files in directory ");
     hyperlinked_path(zD, &title);
-    @ <h2>%s(blob_str(&title))</h2>
+    @ <h2>%s(blob_str(&title))
     blob_reset(&title);
     zPrefix = mprintf("%h/", zD);
   }else{
-    @ <h2>Files in the top-level directory</h2>
+    @ <h2>Files in the top-level directory
     zPrefix = "";
+  }
+  if( zCI ){
+    char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
+    char zShort[20];
+    memcpy(zShort, zUuid, 10);
+    zShort[10] = 0;
+    @ of check-in [<a href="vinfo?name=%T(zUuid)">%s(zShort)</a>]</h2>
+    zSubdirLink = mprintf("%s/dir?ci=%s&name=%T", g.zBaseURL, zUuid, zPrefix);
+    if( zD ){
+      style_submenu_element("Top", "Top", "%s/dir?ci=%s", g.zBaseURL, zUuid);
+    }
+  }else{
+    @ </h2>
+    zSubdirLink = mprintf("%s/dir?name=%T", g.zBaseURL, zPrefix);
   }
 
   /* Compute the temporary table "localfiles" containing the names
   ** of all files and subdirectories in the zD[] directory.
   **
   ** Subdirectory names begin with "/".  This causes them to sort
   ** first and it also gives us an easy way to distinguish files
   ** from directories in the loop that follows.
   */
+  db_multi_exec(
+     "CREATE TEMP TABLE localfiles(x UNIQUE NOT NULL, u);"
+     "CREATE TEMP TABLE allfiles(x UNIQUE NOT NULL, u);"
+  );
+  if( zCI ){
+    Stmt ins;
+    int i;
+    db_prepare(&ins, "INSERT INTO allfiles VALUES(:x, :u)");
+    for(i=0; i<m.nFile; i++){
+      db_bind_text(&ins, ":x", m.aFile[i].zName);
+      db_bind_text(&ins, ":u", m.aFile[i].zUuid);
+      db_step(&ins);
+      db_reset(&ins);
+    }
+    db_finalize(&ins);
+  }else{
+    db_multi_exec(
+      "INSERT INTO allfiles SELECT name, NULL FROM filename"
+    );
+  }
   if( zD ){
     db_multi_exec(
-       "CREATE TEMP TABLE localfiles(x UNIQUE NOT NULL);"
        "INSERT OR IGNORE INTO localfiles "
-       "  SELECT pathelement(name,%d) FROM filename"
-       "   WHERE +name GLOB '%q/*'",
+       "  SELECT pathelement(x,%d), u FROM allfiles"
+       "   WHERE x GLOB '%q/*'",
        strlen(zD)+1, zD
     );
   }else{
     db_multi_exec(
-       "CREATE TEMP TABLE localfiles(x UNIQUE NOT NULL);"
        "INSERT OR IGNORE INTO localfiles "
-       "  SELECT pathelement(name,0) FROM filename"
+       "  SELECT pathelement(x,0), u FROM allfiles"
     );
   }
 
   /* Generate a multi-column table listing the contents of zD[]
   ** directory.
@@ -164,11 +209,11 @@
   */
   mxLen = db_int(12, "SELECT max(length(x)) FROM localfiles");
   cnt = db_int(0, "SELECT count(*) FROM localfiles");
   nCol = 4;
   nRow = (cnt+nCol-1)/nCol;
-  db_prepare(&q, "SELECT x FROM localfiles ORDER BY x");
+  db_prepare(&q, "SELECT x, u FROM localfiles ORDER BY x");
   @ <table border="0" width="100%%"><tr><td valign="top" width="25%%">
   i = 0;
   while( db_step(&q)==SQLITE_ROW ){
     const char *zFName;
     if( i==nRow ){
@@ -177,16 +222,19 @@
     }
     i++;
     zFName = db_column_text(&q, 0);
     if( zFName[0]=='/' ){
       zFName++;
-      @ <li><a href="%s(g.zBaseURL)/dir?name=%T(zPrefix)%T(zFName)">
+      @ <li><a href="%s(zSubdirLink)%T(zFName)">
       @     %h(zFName)/</a></li>
+    }else if( zCI ){
+      const char *zUuid = db_column_text(&q, 1);
+      @ <li><a href="%s(g.zBaseURL)/artifact?name=%s(zUuid)">%h(zFName)</a>
     }else{
       @ <li><a href="%s(g.zBaseURL)/finfo?name=%T(zPrefix)%T(zFName)">
       @     %h(zFName)</a></li>
     }
   }
   db_finalize(&q);
   @ </td></tr></table>
   style_footer();
 }

Modified src/info.c from [b42d745af6] to [8b65dc436f].

@@ -324,10 +324,11 @@
   }
 }
 
 
 /*
+** WEBPAGE: vinfo
 ** WEBPAGE: ci
 ** URL:  /ci?name=RID|ARTIFACTID
 **
 ** Return information about a baseline
 */
@@ -425,10 +426,11 @@
       db_finalize(&q);
       @ </td></tr>
       @ <tr><th>Commands:</th>
       @   <td>
       @     <a href="%s(g.zBaseURL)/vdiff/%d(rid)">diff</a>
+      @     | <a href="%s(g.zBaseURL)/dir?ci=%s(zShortUuid)">files</a>
       @     | <a href="%s(g.zBaseURL)/zip/%s(zProjName)-%s(zShortUuid).zip?uuid=%s(zUuid)">
       @         ZIP archive</a>
       @     | <a href="%s(g.zBaseURL)/artifact/%d(rid)">manifest</a>
       if( g.okWrite ){
         @     | <a href="%s(g.zBaseURL)/ci_edit?r=%d(rid)">edit</a>
@@ -736,11 +738,12 @@
 **     * date of check-in
 **     * Comment & user
 */
 static void object_description(
   int rid,                 /* The artifact ID */
-  int linkToView           /* Add viewer link if true */
+  int linkToView,          /* Add viewer link if true */
+  Blob *pDownloadName      /* Fill with an appropriate download name */
 ){
   Stmt q;
   int cnt = 0;
   int nWiki = 0;
   db_prepare(&q,
@@ -771,10 +774,13 @@
     @ <a href="%s(g.zBaseURL)/finfo?name=%T(zName)">%h(zName)</a>
     @ uuid %s(zFuuid) part of check-in
     hyperlink_to_uuid(zVers);
     @ %w(zCom) by %h(zUser) on %s(zDate).
     cnt++;
+    if( pDownloadName && blob_size(pDownloadName)==0 ){
+      blob_append(pDownloadName, zName, -1);
+    }
   }
   db_finalize(&q);
   db_prepare(&q,
     "SELECT substr(tagname, 6, 10000), datetime(event.mtime),"
     "       coalesce(event.euser, event.user), uuid"
@@ -798,10 +804,13 @@
     }
     @ [<a href="%s(g.zBaseURL)/wiki?name=%t(zPagename)">%h(zPagename)</a>]
     @ uuid %s(zUuid) by %h(zUser) on %s(zDate).
     nWiki++;
     cnt++;
+    if( pDownloadName && blob_size(pDownloadName)==0 ){
+      blob_append(pDownloadName, zPagename, -1);
+    }
   }
   db_finalize(&q);
   if( nWiki==0 ){
     db_prepare(&q,
       "SELECT datetime(mtime), user, comment, uuid, type"
@@ -828,17 +837,23 @@
       }else{
         @ Control file referencing
       }
       hyperlink_to_uuid(zUuid);
       @ %w(zCom) by %h(zUser) on %s(zDate).
+      if( pDownloadName && blob_size(pDownloadName)==0 ){
+        blob_append(pDownloadName, zUuid, -1);
+      }
       cnt++;
     }
     db_finalize(&q);
   }
   if( cnt==0 ){
     char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
     @ Control file %s(zUuid).
+    if( pDownloadName && blob_size(pDownloadName)==0 ){
+      blob_append(pDownloadName, zUuid, -1);
+    }
   }else if( linkToView ){
     @ <a href="%s(g.zBaseURL)/artifact/%d(rid)">[view]</a>
   }
 }
 
@@ -856,15 +871,15 @@
   login_check_credentials();
   if( !g.okRead ){ login_needed(); return; }
   style_header("Diff");
   @ <h2>Differences From:</h2>
   @ <blockquote>
-  object_description(v1, 1);
+  object_description(v1, 1, 0);
   @ </blockquote>
   @ <h2>To:</h2>
   @ <blockquote>
-  object_description(v2, 1);
+  object_description(v2, 1, 0);
   @ </blockquote>
   @ <hr>
   @ <blockquote><pre>
   content_get(v1, &c1);
   content_get(v2, &c2);
@@ -959,10 +974,11 @@
 ** as preformatted text.
 */
 void hexdump_page(void){
   int rid;
   Blob content;
+  Blob downloadName;
 
   rid = name_to_rid(PD("name","0"));
   login_check_credentials();
   if( !g.okRead ){ login_needed(); return; }
   if( rid==0 ){ cgi_redirect("/home"); }
@@ -977,11 +993,14 @@
     }
   }
   style_header("Hex Artifact Content");
   @ <h2>Hexadecimal Content Of:</h2>
   @ <blockquote>
-  object_description(rid, 0);
+  blob_zero(&downloadName);
+  object_description(rid, 0, &downloadName);
+  style_submenu_element("Download", "Download",
+        "%s/raw/%T?name=%d", g.zBaseURL, blob_str(&downloadName), rid);
   @ </blockquote>
   @ <hr>
   content_get(rid, &content);
   @ <blockquote><pre>
   hexdump(&content);
@@ -998,10 +1017,11 @@
 */
 void artifact_page(void){
   int rid;
   Blob content;
   const char *zMime;
+  Blob downloadName;
 
   rid = name_to_rid(PD("name","0"));
   login_check_credentials();
   if( !g.okRead ){ login_needed(); return; }
   if( rid==0 ){ cgi_redirect("/home"); }
@@ -1016,11 +1036,14 @@
     }
   }
   style_header("Artifact Content");
   @ <h2>Content Of:</h2>
   @ <blockquote>
-  object_description(rid, 0);
+  blob_zero(&downloadName);
+  object_description(rid, 0, &downloadName);
+  style_submenu_element("Download", "Download",
+          "%s/raw/%T?name=%d", g.zTop, blob_str(&downloadName), rid);
   @ </blockquote>
   @ <hr>
   @ <blockquote>
   content_get(rid, &content);
   zMime = mimetype_from_content(&content);