1 (* COCANWIKI - a wiki written in Objective CAML.
2 * Written by Richard W.M. Jones <rich@merjis.com>.
3 * Copyright (C) 2004 Merjis Ltd.
4 * $Id: cocanwiki_diff.ml,v 1.3 2004/11/01 12:57:53 rich Exp $
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; see the file COPYING. If not, write to
18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
30 (* Convenience code for generating diffs between versions. See diff.ml
31 * and edit.ml which both use this code.
33 let page_for_diff css sections =
35 (List.map (fun (sectionname, content) ->
36 "HEADING: " ^ sectionname ^ "\n\n" ^
37 content ^ "\n\n") sections)) ^
40 let le_re = Pcre.regexp "\r?\n"
41 let le_subst = Pcre.subst "\n"
43 let diff_cmd old_page new_page =
44 (* Convert line-endings in the input files from \r\n to \n. Diff
45 * can get confused by the \r characters, particularly in side-by-side
46 * mode when asked to expand tabs (-y -t).
48 let f = Pcre.replace ~rex:le_re ~itempl:le_subst in
49 let new_page = f new_page in
50 let old_page = f old_page in
52 let new_filename = output_tempfile new_page in
53 let old_filename = output_tempfile old_page in
55 (* Side-by-side mode was good, but stupidly implemented. It's
58 let diff_sidebyside = false in
61 if not diff_sidebyside then
65 let options = options ^ " -t -b -B" in
67 let cmd = sprintf "diff %s %s %s ||:" options old_filename new_filename in
68 let diff = pget cmd in
70 (* Remove the temporary files. *)
71 unlink new_filename; unlink old_filename;
74 if not diff_sidebyside then
76 _ :: _ :: diff -> diff
80 String.concat "\n" diff
82 let get_version_for_diff (dbh : Dbi.connection) version =
83 if version = 0 then "" else (
84 let sth = dbh#prepare_cached "select coalesce (css, '') as css
85 from pages where id = ?" in
86 sth#execute [`Int version];
88 let css = sth#fetch1string () in
90 let sth = dbh#prepare_cached "select coalesce (sectionname, ''), content
91 from contents where pageid = ?
93 sth#execute [`Int version];
97 [`String sectionname; `String content] ->
99 | _ -> assert false) in
100 let page = page_for_diff css sections in
105 let get_diff (dbh : Dbi.connection) hostid page ?old_version ~version ()=
107 match old_version with
108 | Some version -> version
110 let sth = dbh#prepare_cached "select id from pages
112 and url_deleted = ? and id < ?
113 order by 1 desc limit 1" in
114 sth#execute [`Int hostid; `String page; `Int version];
117 with Not_found -> 0 in
119 (* Get the two versions. *)
120 let new_page = get_version_for_diff dbh version in
121 let old_page = get_version_for_diff dbh old_version in
123 (* Compute the diff of the two versions. *)
124 let diff = diff_cmd old_page new_page in