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

JJ <[email protected]> Fri, 21 Nov 2008 10:59:42 -0600
Newsgroups gmane.comp.version-control.cvs.viewcvs.devel
Message-ID <[email protected]>
>
>      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.  :-)
>>>
>>>
>>
After thinking this over some more, I decided that only using mime types
instead of file extensions makes sense (i.e. You Were Right!) and is
cleaner.

Here is a new patch that allows people to either list mime types that
*should* have prefer_markup set (in the prefer_markup_mime_types variable)
or list mime types that *should not* have prefer_markup set (in the
no_prefer_markup_mime_types variable).

If no values are specified in prefer_markup_mime_types, prefer_markup is set
for *all* mime types.  To make this work right I had to use an empty list as
the default value of prefer_markup_mime_types in config.py, but I still
specify text/* in viewvc.conf.  That goes against what you said earlier, but
it was a necessary change to default to all mime types, and the flexibility
it provides is quite nice.

I also maintained the prefer_markup_default variable, which allows people to
specify if prefer_markup should be set for files with no mime type.

Please let me know what you think.

JJ

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
patch-20081121-1.txt (text/plain, 11.9 KB)
Index: viewvc.conf.dist
===================================================================
--- viewvc.conf.dist	(revision 2057)
+++ viewvc.conf.dist	(working copy)
@@ -339,6 +339,19 @@
 # by browsers).
 svn_ignore_mimetype = 0
 
+# List of mime types for files that should have prefer_markup set.
+# They can be specified using UNIX shell wildcards.
+# If not set, all mime types will have prefer_markup set.
+prefer_markup_mime_types = text/*
+
+# List of mime types that should not have prefer_markup set.
+# They can be specified using UNIX shell wildcards.
+# These values will override those in prefer_markup_mime_types.
+no_prefer_markup_mime_types =
+
+# If a file has no mime type, should prefer_markup be set 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 2057)
+++ 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 2057)
+++ 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 2057)
+++ 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: templates/revision.ezt
===================================================================
--- templates/revision.ezt	(revision 2057)
+++ templates/revision.ezt	(working copy)
@@ -61,9 +61,19 @@
   [if-any changes]
    [for changes]
     <tr class="vc_row_[if-index changes even]even[else]odd[end]">
-      <td>[if-any changes.view_href]<a href="[changes.view_href]" title="View [is changes.pathtype "dir"]Directory[else]File[end] Contents">[end]<img src="[docroot]/images/[is changes.pathtype "dir"]dir[else]text[end].png" class="vc_icon" alt="Directory" />[changes.path][is changes.pathtype "dir"]/[end][if-any changes.view_href]</a>[end]
-      [if-any changes.is_copy]<br /><em>(Copied from [changes.copy_path], r[changes.copy_rev])</em>[end]
+
+      <td>
+        [is changes.pathtype "file"]
+          [if-any changes.prefer_markup][if-any changes.view_href]<a href="[changes.view_href]" title="View File Contents">[end][end]
+             <img src="[docroot]/images/text.png" class="vc_icon" alt="File" />[changes.path][if-any changes.prefer_markup][if-any changes.view_href]</a>[end][end]
+        [else]
+          [if-any changes.view_href]<a href="[changes.view_href]" title="View Directory Contents">[end]
+             <img src="[docroot]/images/dir.png" class="vc_icon" alt="Directory" />[changes.path]/[if-any changes.view_href]</a>[end]
+        [end]
+        [if-any changes.is_copy]<br /><em>(Copied from [changes.copy_path], r[changes.copy_rev])</em>[end]
       </td>
+
+
       <td>[if-any changes.log_href]<a href="[changes.log_href]" title="View Log">[end][changes.action][if-any changes.log_href]</a>[end]
           [if-any changes.text_mods], [if-any changes.diff_href]<a href="[changes.diff_href]" title="View Diff">[end]text changed[if-any changes.diff_href]</a>[end][end]
           [if-any changes.prop_mods], props changed[end]
Index: lib/viewvc.py
===================================================================
--- lib/viewvc.py	(revision 2057)
+++ 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,34 @@
 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_prefer_markup_mime_type(mime_type, cfg):
+  if not mime_type:
+    # Return the default value.
+    return cfg.options.prefer_markup_default
 
+  # Is it in no_prefer_markup_mime_types?
+  for m in cfg.options.no_prefer_markup_mime_types:
+    if fnmatch.fnmatch(mime_type, m):
+      return False
+  # Is it in prefer_markup_mime_types?
+  for m in cfg.options.prefer_markup_mime_types:
+    if fnmatch.fnmatch(mime_type, m):
+      return True
+
+  # If prefer_markup_mime_types isn't set, default
+  # to True for all mime types.
+  if not cfg.options.prefer_markup_mime_types:
+    return True
+  # prefer_markup_mime_types is set, but our mime type isn't in it.
+  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
@@ -987,8 +1006,8 @@
   # very useful marked up. If the mime type is totally unknown (happens when
   # 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))):
+  if (('markup' in cfg.options.allowed_views) and
+      (is_viewable_image(mime_type) or is_prefer_markup_mime_type(mime_type, cfg))):
     return view_markup
   return view_checkout
 
@@ -1052,7 +1071,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 _item(view_href=view_href,
                download_href=download_href,
@@ -2410,7 +2429,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
@@ -3221,6 +3240,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.
@@ -3231,13 +3251,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:
@@ -3247,6 +3260,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,
@@ -3577,7 +3600,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 2057)
+++ lib/config.py	(working copy)
@@ -40,7 +40,9 @@
 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',
+                        'prefer_markup_mime_types',
+                        'no_prefer_markup_mime_types')
 
   def __init__(self):
     for section in self._sections:
@@ -221,6 +223,9 @@
     self.options.generate_etags = 1
     self.options.svn_ignore_mimetype = 0
     self.options.svn_config_dir = None
+    self.options.prefer_markup_mime_types = []
+    self.options.no_prefer_markup_mime_types = []
+    self.options.prefer_markup_default = 0
     self.options.use_rcsparse = 0
     self.options.sort_by = 'file'
     self.options.sort_group_dirs = 1