Re: [viewvc-dev] Re: [viewvc-users] Don't display binary files

JJ <[email protected]> Thu, 20 Nov 2008 11:32:33 -0600
Newsgroups gmane.comp.version-control.cvs.viewcvs.devel
Message-ID <eed30ed90811200932s11f06c2bhddc3fec96ba6fa82__44232.3413248689$1227202450$gmane$org@mail.gmail.com>
On Thu, Nov 20, 2008 at 11:28 AM, JJ <[email protected]> wrote:

>   On Thu, Nov 20, 2008 at 10:28 AM, C. Michael Pilato <[email protected]
> > wrote:
>
>> JJ wrote:
>> >     I like this, but I wouldn't add a new config file.  I'd just add a
>> new
>> >     configuration option that follows the format of our existing
>> multi-value
>> >     options.  And I'd let the values take wildcards (text/*,
>> >     application/*-xml,
>> >     etc.), too, so you wouldn't have to specify every single little
>> thing.
>> >
>> > Patch attached.  I also need to clean up the default templates
>> > to respect prefer_markup values.
>>
>> Nice patch, JJ.  It needs a couple of tweaks, though:
>>
>>   - the viewvc.conf.dist file should, if presenting an uncommented option,
>>     present the same option value that is used as the default in
>>     lib/config.py.  In this case, I think you got lib/config.py right
>>     (in that we only want to assume that text/* is text by default),
>>     but the viewvc.conf.dist file is wrong.  Just make the value in
>>     that file "text/*", and maybe add a second, commented-out example
>>     that shows some of the other types folks might want in there.
>>
>>   - I don't like the "convert to a valid regexp" logic.  If we're going
>>     to use regexps, let's expose that directly to users.  If we really
>>     only care about '*' as a wildcard, then maybe the 'fnmatch' module
>>     is what you want to use for comparisons (since mime types are
>>     slash-delimited like paths are).
>>
>> --
>> C. Michael Pilato <[email protected]>
>> CollabNet   <>   www.collab.net   <>   Distributed Development On Demand
>>
>
> How about this patch?  It includes the following changes.
>
> * text_mime_types - as described before, but matching is now done with
> fnmatch, and the config.py defaults and viewvc.conf match.
>
> * text_file_extensions - List of file extensions to for text files.  Mime
> types really only make sense in the browser world.  Not all files are meant
> to view in a browser though, so making people add an entry into a mime.types
> file for them doesn't make sense.  This also uses fnmatch, and by default it
> is commented out, though it contains an example so people know how to format
> it.
>
> * prefer_markup_default - specifies what should be done if we can determine
> if it is text file or viewable image based on mime type or file extension.
> Default to 0 since that seems like the safest thing to do, though you could
> change it if you prefer.
>
> * Finished cleaning up templates to properly display links based on
> prefer_markup value.  They weren't doing so before.
>
> * Made changes.prefer_markup available in revisions.ezt, since it wasn't
> before and should have been.
>
> This is working nicely for me.  I hope you're okay with the changes.  :-)
>
> JJ
>
>

Whoops, I attached the wrong file.  I should be naming my patch files
something different each time so I'm not confused.

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
patch-20081120-1.txt (text/plain, 9.7 KB)
Index: viewvc.conf.dist
===================================================================
--- viewvc.conf.dist	(revision 2056)
+++ viewvc.conf.dist	(working copy)
@@ -339,6 +339,18 @@
 # by browsers).
 svn_ignore_mimetype = 0
 
+# List of text file mime types, which can be specified using UNIX shell
+# wildcards.  These files will have prefer_markup set.
+text_mime_types = text/*
+
+# List of text file extensions, which can be specified using UNIX shell
+# wildcards.  These files will have prefer_markup set.
+#text_file_extensions = java, jsp, properties, xml
+
+# If we can't determine if the file is a text file via mime type or
+# file extension, should ViewVC set prefer_markup for the file anyway?
+prefer_markup_default = 0
+
 # svn_config_dir: Path of the Subversion runtime configuration
 # directory ViewVC should consult for various things, including cached
 # remote authentication credentials.  If unset, Subversion will use
Index: templates/log.ezt
===================================================================
--- templates/log.ezt	(revision 2056)
+++ templates/log.ezt	(working copy)
@@ -22,21 +22,23 @@
     Revision [is roottype "svn"]<a href="[entries.revision_href]"><strong>[entries.rev]</strong></a>[else]<strong>[entries.rev]</strong>[end] -
     [if-any entries.view_href]
       [is pathtype "file"]
-        (<a href="[entries.view_href]">view</a>)
+        [if-any prefer_markup](<a href="[entries.view_href]">view</a>)[end]
       [else]
         <a href="[entries.view_href]">Directory Listing</a>
       [end]
     [end]
     [if-any entries.download_href](<a href="[entries.download_href]">download</a>)[end]
-    [if-any entries.download_text_href](<a href="[entries.download_text_href]">as text</a>)[end]
-    [if-any entries.annotate_href](<a href="[entries.annotate_href]">annotate</a>)[end]
+    [if-any prefer_markup]
+      [if-any entries.download_text_href](<a href="[entries.download_text_href]">as text</a>)[end]
+      [if-any entries.annotate_href](<a href="[entries.annotate_href]">annotate</a>)[end]
 
-    [is pathtype "file"]
-      [# if you don't want to allow select for diffs then remove this section]
-      [is entries.rev rev_selected]
-        - <strong>[[]selected]</strong>
-      [else]
-        - <a href="[entries.sel_for_diff_href]">[[]select for diffs]</a>
+      [is pathtype "file"]
+        [# if you don't want to allow select for diffs then remove this section]
+        [is entries.rev rev_selected]
+          - <strong>[[]selected]</strong>
+        [else]
+          - <a href="[entries.sel_for_diff_href]">[[]select for diffs]</a>
+        [end]
       [end]
     [end]
   [end]
Index: templates/include/log_footer.ezt
===================================================================
--- templates/include/log_footer.ezt	(revision 2056)
+++ templates/include/log_footer.ezt	(working copy)
@@ -1,7 +1,9 @@
 [include "paging.ezt"]
 
 [is pathtype "file"]
-  [include "diff_form.ezt"]
+  [if-any prefer_markup]
+    [include "diff_form.ezt"]
+  [end]
 [end]
 
 [include "sort.ezt"]
Index: templates/include/log_header.ezt
===================================================================
--- templates/include/log_header.ezt	(revision 2056)
+++ templates/include/log_header.ezt	(working copy)
@@ -23,10 +23,12 @@
 <tr>
   <td>Links to HEAD:</td>
   <td>
-    (<a href="[head_view_href]">view</a>)
+    [if-any prefer_markup](<a href="[head_view_href]">view</a>)[end]
     [if-any head_download_href](<a href="[head_download_href]">download</a>)[end]
-    [if-any head_download_text_href](<a href="[head_download_text_href]">as text</a>)[end]
-    [if-any head_annotate_href](<a href="[head_annotate_href]">annotate</a>)[end]
+    [if-any prefer_markup]
+      [if-any head_download_text_href](<a href="[head_download_text_href]">as text</a>)[end]
+      [if-any head_annotate_href](<a href="[head_annotate_href]">annotate</a>)[end]
+    [end]
   </td>
 </tr>
 [end]
@@ -37,8 +39,10 @@
   <td>
     (<a href="[tag_view_href]">view</a>)
     [if-any tag_download_href](<a href="[tag_download_href]">download</a>)[end]
-    [if-any tag_download_text_href](<a href="[tag_download_text_href]">as text</a>)[end]
-    [if-any tag_annotate_href](<a href="[tag_annotate_href]">annotate</a>)[end]
+    [if-any prefer_markup]
+      [if-any tag_download_text_href](<a href="[tag_download_text_href]">as text</a>)[end]
+      [if-any tag_annotate_href](<a href="[tag_annotate_href]">annotate</a>)[end]
+    [end]
   </td>
 </tr>
 [end]
Index: lib/viewvc.py
===================================================================
--- lib/viewvc.py	(revision 2056)
+++ lib/viewvc.py	(working copy)
@@ -25,6 +25,7 @@
 import sys
 import os
 import cgi
+import fnmatch
 import gzip
 import mimetypes
 import re
@@ -969,16 +970,27 @@
 def is_viewable_image(mime_type):
   return mime_type and mime_type in ('image/gif', 'image/jpeg', 'image/png')
 
-def is_text(mime_type):
-  return not mime_type or mime_type[:5] == 'text/'
+def is_text_mime_type(mime_type, cfg):
+  if mime_type:
+    for m in cfg.options.text_mime_types:
+      if fnmatch.fnmatch(mime_type, m):
+        return True
+  return False
 
+def is_text_extension(filename, cfg):
+  ext = filename.split(".")[-1]
+  for e in cfg.options.text_file_extensions:
+    if fnmatch.fnmatch(ext, e):
+      return True
+  return False
+
 def is_cvsroot_path(roottype, path_parts):
   return roottype == 'cvs' and path_parts and path_parts[0] == 'CVSROOT'
 
 def is_plain_text(mime_type):
   return not mime_type or mime_type == 'text/plain'
 
-def default_view(mime_type, cfg):
+def default_view(filename, mime_type, cfg):
   "Determine whether file should be viewed through markup page or sent raw"
   # If the mime type is text/anything or a supported image format we view
   # through the markup page. If the mime type is something else, we send
@@ -988,7 +1000,8 @@
   # we encounter an unrecognized file extension) we also view it through
   # the markup page since that's better than sending it text/plain.
   if ('markup' in cfg.options.allowed_views and 
-      (is_viewable_image(mime_type) or is_text(mime_type))):
+      (is_viewable_image(mime_type) or is_text_mime_type(mime_type, cfg) \
+       or is_text_extension(filename, cfg))) or cfg.options.prefer_markup_default:
     return view_markup
   return view_checkout
 
@@ -1040,7 +1053,7 @@
                                     params={'revision': rev},
                                     escape=1)
 
-  prefer_markup = default_view(mime_type, request.cfg) == view_markup
+  prefer_markup = default_view(where, mime_type, request.cfg) == view_markup
 
   return view_href, download_href, download_text_href, \
          annotate_href, revision_href, ezt.boolean(prefer_markup)
@@ -2386,7 +2399,7 @@
 
   imagesrc = request.get_url(view_func=view_cvsgraph_image, escape=1)
   mime_type = guess_mime(request.where)
-  view = default_view(mime_type, cfg)
+  view = default_view(request.where, mime_type, cfg)
   up_where = _path_join(request.path_parts[:-1])
 
   # Create an image map
@@ -3185,6 +3198,7 @@
   # Add the hrefs, types, and prev info
   for change in changes:
     change.view_href = change.diff_href = change.type = change.log_href = None
+    change.prefer_markup = ezt.boolean(0)
 
     # If the path is newly added, don't claim text or property
     # modifications.
@@ -3195,13 +3209,6 @@
 
     # Calculate the view link URLs (for which we must have a pathtype).
     if change.pathtype:
-      view_func = None
-      if change.pathtype is vclib.FILE \
-         and 'markup' in cfg.options.allowed_views:
-        view_func = view_markup
-      elif change.pathtype is vclib.DIR:
-        view_func = view_directory
-
       path = _path_join(change.path_parts)
       base_path = _path_join(change.base_path_parts)
       if change.action == vclib.DELETED:
@@ -3211,6 +3218,16 @@
         link_rev = str(rev)
         link_where = path
 
+      view_func = None
+      if change.pathtype is vclib.FILE \
+         and 'markup' in cfg.options.allowed_views:
+        view_func = view_markup
+        mime_type = guess_mime(link_where)
+        change.prefer_markup = ezt.boolean(default_view(link_where, mime_type, cfg) == view_markup)
+      elif change.pathtype is vclib.DIR:
+        view_func = view_directory
+
+
       change.view_href = request.get_url(view_func=view_func,
                                          where=link_where,
                                          pathtype=change.pathtype,
@@ -3541,7 +3558,7 @@
                                   where=where, pathtype=vclib.FILE,
                                   params=diff_href_params, escape=1)
     mime_type = calculate_mime_type(request, path_parts, exam_rev)
-    prefer_markup = ezt.boolean(default_view(mime_type, cfg) == view_markup)
+    prefer_markup = ezt.boolean(default_view(where, mime_type, cfg) == view_markup)
 
     # Update plus/minus line change count.
     plus = int(f.GetPlusCount())
Index: lib/config.py
===================================================================
--- lib/config.py	(revision 2056)
+++ lib/config.py	(working copy)
@@ -40,7 +40,8 @@
 class Config:
   _sections = ('general', 'utilities', 'options', 'cvsdb', 'templates')
   _force_multi_value = ('cvs_roots', 'svn_roots', 'languages', 'kv_files',
-                        'root_parents', 'allowed_views')
+                        'root_parents', 'allowed_views', 'text_mime_types',
+                        'text_file_extensions')
 
   def __init__(self):
     for section in self._sections:
@@ -221,6 +222,9 @@
     self.options.generate_etags = 1
     self.options.svn_ignore_mimetype = 0
     self.options.svn_config_dir = None
+    self.options.text_mime_types = ['text/*']
+    self.options.text_file_extensions = []
+    self.options.prefer_markup_default = 0
     self.options.use_rcsparse = 0
     self.options.sort_by = 'file'
     self.options.sort_group_dirs = 1