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.8 2006/08/14 11:36:50 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.
31 (* Convenience code for generating diffs between versions. See diff.ml
32 * and edit.ml which both use this code.
34 let page_for_diff model css =
35 let title_or_url = match model.pt with Page t -> t | Title t -> t in
36 "Title or URL: " ^ title_or_url ^ "\n" ^
37 "Description: " ^ model.description ^ "\n\n" ^
38 (match model.keywords with
40 | Some keywords -> "Keywords: " ^ keywords ^ "\n\n") ^
41 (match model.redirect with
43 | Some redirect -> "Redirect: " ^ redirect ^ "\n\n") ^
45 (match model.noodp with
46 | None -> "inherit sitewide default"
47 | Some noodp -> string_of_bool noodp) ^ "\n\n" ^
50 fun (sectionname, divname, jsgo, content) ->
51 (match sectionname with
53 | Some sectionname -> "HEADING: " ^ sectionname ^ "\n\n") ^
57 | Some divname -> "CSS Id: " ^ divname ^ "\n") ^
60 | Some jsgo -> "Javascript Onclick: " ^ jsgo ^ "\n") ^
66 | Some css -> "CSS:\n\n" ^ css ^ "\n")
68 let le_re = Pcre.regexp "\r?\n"
69 let le_subst = Pcre.subst "\n"
71 let diff_cmd old_page new_page =
72 (* Convert line-endings in the input files from \r\n to \n. Diff
73 * can get confused by the \r characters, particularly in side-by-side
74 * mode when asked to expand tabs (-y -t).
76 let f = Pcre.replace ~rex:le_re ~itempl:le_subst in
77 let new_page = f new_page in
78 let old_page = f old_page in
80 let new_filename = output_tempfile new_page in
81 let old_filename = output_tempfile old_page in
83 (* Side-by-side mode was good, but stupidly implemented. It's
86 let diff_sidebyside = false in
89 if not diff_sidebyside then
93 let options = options ^ " -t -b -B" in
95 let cmd = sprintf "diff %s %s %s ||:" options old_filename new_filename in
96 let diff = pget cmd in
98 (* Remove the temporary files. *)
99 unlink new_filename; unlink old_filename;
102 if not diff_sidebyside then
104 _ :: _ :: diff -> diff
108 String.concat "\n" diff
110 let get_version_for_diff dbh version =
111 if version = 0l then ""
113 let title, description, keywords, noodp, redirect, css = List.hd (
115 "select title, description, keywords, noodp, redirect, css from pages
119 let contents_ = PGSQL(dbh)
120 "select sectionname, divname, jsgo, content
121 from contents where pageid = $version
122 order by ordering" in
124 let model = { id = version;
126 description = description;
130 contents_ = contents_ } in
132 let page = page_for_diff model css in
137 let get_diff dbh hostid page ?old_version ~version ()=
139 match old_version with
140 | Some version -> version
145 "select id from pages
146 where hostid = $hostid
147 and url_deleted = $page
149 order by 1 desc limit 1"
152 Not_found | ExtList.List.Empty_list | Failure "hd" -> 0l in
154 (* Get the two versions. *)
155 let new_page = get_version_for_diff dbh version in
156 let old_page = get_version_for_diff dbh old_version in
158 (* Compute the diff of the two versions. *)
159 let diff = diff_cmd old_page new_page in