[kernel] r7594 - dists/trunk/scripts

Sven Luther luther at costa.debian.org
Tue Oct 10 21:05:33 UTC 2006


Author: luther
Date: Tue Oct 10 21:05:32 2006
New Revision: 7594

Modified:
   dists/trunk/scripts/kconfig.ml

Log:
Added support for diffing config files in kconfig.ml.


Modified: dists/trunk/scripts/kconfig.ml
==============================================================================
--- dists/trunk/scripts/kconfig.ml	(original)
+++ dists/trunk/scripts/kconfig.ml	Tue Oct 10 21:05:32 2006
@@ -1,41 +1,120 @@
 #!/usr/bin/ocamlrun /usr/bin/ocaml
+(*
+ * kconfig.ml Copyright (C) 2006 Sven Luther <sl at powerlinux.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by * the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+(*
+ * Syntax :
+ *  kconfig.ml <action> [-bs sourcedir] <file> [<file>]
+ *    <action> : single | check | create | diff
+ *    <file> : -c <filename> | [-b basedir | -ba basedir]  -a arch [-s subarch] -f flavour
+ *)
+
+let usage_string =
+  "Usage:\n\n" ^
+  "  Check single config file : ./kconfig.ml single -c <filename>\n" ^
+  "  Create config file       : ./kconfig.ml create [ -ba <dir> | -b <dir> ] -a <arch> [ -s <subarch> ] -f <flavour>\n" ^
+  "  Check all config files   : ./kconfig.ml check [ -ba <dir> | -b <dir> ] [ -bs <dir> ]\n" ^
+  "  Diff two config files    : ./kconfig.ml diff [ -ba <dir> | -b <dir> ] config config\n" ^
+  "           where config is : (-c <filename> | -a <arch> [ -s <subarch> ] -f <flavour>)\n" ^
+  "\nOptions:\n"
+
+(* Command line argument parsing *)
+exception Bad_action of string
+exception Double_action of string
+exception Bad_args of string
+
+type action = Single | Check | Create | Diff | NoAction | Help
+let action = ref NoAction
+let set_action a =
+  if !action != NoAction then raise (Double_action a) else
+  match a with 
+  | "check" ->  action := Check
+  | "create" ->  action := Create
+  | "diff" ->  action := Diff
+  | "single" ->  action := Single
+  | _ -> raise (Bad_action a)
+let string_of_action = function
+  | Single -> "single"
+  | Check -> "check"
+  | Create -> "create"
+  | Diff ->  "diff"
+  | NoAction ->  "NoAction"
+  | Help ->  "Help"
 
-(* Command line arguments parsing *)
 let basedir = ref "debian/arch"
 let sourcedir = ref "."
-let arch = ref ""
-let subarch = ref ""
-let flavour = ref ""
-let config_name = ref ""
-let verbose = ref false
-let archindir = ref false
+let set_basedir archindir dir =
+  basedir := if archindir then Filename.dirname dir else dir
 
-type action = Single | Create | Check
-let action = ref Create
+type kind = TConfig | TArch | TSubarch | TFlavour
+type temp = (kind * string) list
+let temp : temp ref = ref []
+let set_temp k s = temp := (k,s) :: !temp 
+let rec print_temp = function
+  | [] -> ()
+  | (TConfig,s)::t -> Printf.printf "<Config %s>\n" s; print_temp t
+  | (TArch,s)::t -> Printf.printf "<Arch %s>\n" s; print_temp t
+  | (TSubarch,s)::t -> Printf.printf "<Subarch %s>\n" s; print_temp t
+  | (TFlavour,s)::t -> Printf.printf "<Flavour %s>\n" s; print_temp t
+let string_of_temp_error a s l =
+  let rec pte e = function
+  | [] -> e
+  | (TConfig,s)::t -> pte (e ^ (Printf.sprintf "-c %s " s)) t
+  | (TArch,s)::t -> pte (e ^ (Printf.sprintf "-a %s " s)) t
+  | (TSubarch,s)::t -> pte (e ^ (Printf.sprintf "-s %s " s)) t
+  | (TFlavour,s)::t -> pte (e ^ (Printf.sprintf "-f %s " s)) t
+  in
+  (match a with Some a -> Printf.sprintf"-a %s " a | None -> "") ^
+  (match s with Some s -> Printf.sprintf "-s %s " s | None -> "") ^
+  (pte "" l)
+
+type config = Config of string | Flavour of string * string | Subarch of string * string * string
+let config_of_temp t = 
+  let rec config_of_temp ta ts l = match ta, ts, l with
+  | None, None, (TArch,a)::t -> config_of_temp (Some a) None t
+  | Some a, None, (TSubarch,s)::t -> config_of_temp (Some a) (Some s) t
+  | Some a, Some s, (TFlavour,f)::t -> (Subarch (a,s,f))::(config_of_temp None None t)
+  | Some a, None, (TFlavour,f)::t -> (Flavour (a,f))::(config_of_temp None None t)
+  | None, None, (TConfig,f)::t -> (Config f)::(config_of_temp None None t)
+  | None, None, [] -> []
+  | _, _, _ -> raise (Bad_args (string_of_temp_error ta ts l))
+  in config_of_temp None None t 
+
+let rec print_configs = function
+  | [] -> ()
+  | (Config f) :: t -> Printf.printf "Config file: %s\n" f; print_configs t
+  | (Flavour (a,f)) :: t -> Printf.printf "Arch: %s, Flavour: %s\n" a f; print_configs t
+  | (Subarch (a,s,f)) :: t -> Printf.printf "Arch: %s, Subarch: %s, Flavour: %s\n" a s f; print_configs t
 
-let set_action a () = action := a
+let verbose = ref false
 
 let spec = [
-  "-b", Arg.Set_string basedir, "base dir of the arch configurations [default: debian/arch]";
+  "-b", Arg.String (set_basedir false), "specify basedir of the arch configurations [default: debian/arch]";
+  "-ba", Arg.String (set_basedir true), "specify basedir of the arch configurations (after stripping arch dir) [default: debian/arch]";
   "-bs", Arg.Set_string sourcedir, "base source dir containing the patched debian linux source tree [default: .]";
-  "-ba", Arg.Set archindir, "basedir includes arch";
-  "-a", Arg.Set_string arch, "arch";
-  "-s", Arg.Set_string subarch, "subarch";
-  "-f", Arg.Set_string flavour, "flavour";
-  "-v", Arg.Set verbose, "verbose";
-  "-c", Arg.Unit (set_action Check), "check";
+  "-a", Arg.String (set_temp TArch), "specify config arch";
+  "-s", Arg.String (set_temp TSubarch), "specify config subarch";
+  "-f", Arg.String (set_temp TFlavour), "specify config flavour";
+  "-c", Arg.String (set_temp TConfig), "specify config file name";
+  "-v", Arg.Set verbose, "verbose output";
+  "-h", Arg.Unit (function () -> action := Help), "Display this list of options";
 ]
-let usage =
-  "Check single config file : ./kconfig.ml config_file\n" ^
-  "Create config file       : ./kconfig.ml [ -ba ] [ -b basedir ] -a arch [ -s subarch ] -f flavour" ^ "\n" ^
-  "Check all config files   : ./kconfig.ml -c [ -ba ] [ -b basedir ] [ -bs sourcedir ] [ -a arch ] [ -s subarch ] [ -f flavour ]" ^ "\n"
-
-let () = Arg.parse
-  spec
-  (function s -> config_name := s; action := Single) 
-  usage
 
-let usage () = Arg.usage spec usage
+let usage () = Arg.usage spec usage_string
 
 (* Config file parsing *)
 type options =
@@ -113,6 +192,27 @@
   with Sys_error s ->
     if force then raise (Sys_error s) else m
 
+(* Diffing two config files *)
+module Diff = Map.Make (String)
+type diff = Add of options | Del of options | Change of options * options
+let diff_configs a b =
+  let diff1 n v (b,d) = try
+    let v' = C.find n b in
+    let b = C.remove n b in
+    if v = v' then b, d else b, Diff.add n (Change (v,v')) d
+  with Not_found -> b, Diff.add n (Add v) d
+  in
+  let diff2 n v d = Diff.add n (Del v) d in
+  let b,d = C.fold diff1 a (b, Diff.empty) in
+  C.fold diff2 b d
+let print_diff d = 
+  let print_diff n = function
+    | Add v -> Printf.printf "+ "; print_option v
+    | Del v -> Printf.printf "- "; print_option v
+    | Change (v,v') -> Printf.printf "+ "; print_option v; Printf.printf "- "; print_option v'
+  in
+  Diff.iter print_diff d
+
 (* Defines parsing *)
 type define =
   | Defines_Base of string
@@ -175,46 +275,97 @@
 let print_defines m = List.iter print_define m
 
 (* Main functionality *)
-let get_archdir () = if !archindir then Filename.dirname !basedir else !basedir
-
-let do_single () = 
-  try
-    begin if !verbose then Printf.eprintf "Reading config file %s" !config_name end;
-    let config = open_in !config_name in
+let create_config = function 
+  | Config c ->
+    begin if !verbose then Printf.eprintf "Reading config file %s" c end;
+    let config = open_in c in
     let m = parse_config config C.empty in
-    print_config m;
-    close_in config
-  with Sys_error s -> Printf.eprintf "Error: %s\n" s
-
-let do_create () =
-  if !arch <> "" && !flavour <> "" then begin
-      if !verbose then 
-        Printf.eprintf "Creating config file for arch %s, subarch %s, flavour %s (basedir is %s)\n" !arch !subarch !flavour !basedir;
-      let dir = get_archdir () in
-      let m = parse_config_file (dir ^ "/config") C.empty false in
-      let archdir = dir ^ "/" ^ !arch in
-      let m = parse_config_file (archdir ^ "/config") m false in
-      let m, archdir = 
-        if !subarch <> ""  && !subarch <> "none" then 
-          let archdir = archdir ^ "/" ^ !subarch in
-          parse_config_file (archdir ^ "/config") m false, archdir
-        else m, archdir
-      in
-      let m = parse_config_file (archdir ^ "/config." ^ !flavour) m true in
-      print_config m
-    end
-  else
-    usage ()
-    
-let do_check () = 
-  let dir = get_archdir () in
-  begin if !verbose then Printf.eprintf "Checking config files in %s\n" dir end;
-  let m = parse_defines_file (dir ^ "/defines") [] true in
-  print_defines m
+    let () = close_in config in
+    m
+  | Subarch (a,s,f) -> 
+    if !verbose then 
+      Printf.eprintf "Creating config file for arch %s, subarch %s, flavour %s (basedir is %s)\n" a s f !basedir;
+    let m = parse_config_file (!basedir ^ "/config") C.empty false in
+    let archdir = !basedir ^ "/" ^ a in
+    let m = parse_config_file (archdir ^ "/config") m false in
+    let archdir = archdir ^ "/" ^ s in
+    let m = parse_config_file (archdir ^ "/config") m false in
+    parse_config_file (archdir ^ "/config." ^ f) m true
+  | Flavour (a,f) ->
+    if !verbose then 
+      Printf.eprintf "Creating config file for arch %s, flavour %s (basedir is %s)\n" a f !basedir;
+    let m = parse_config_file (!basedir ^ "/config") C.empty false in
+    let archdir = !basedir ^ "/" ^ a in
+    let m = parse_config_file (archdir ^ "/config") m false in
+    parse_config_file (archdir ^ "/config." ^ f) m true
+
+let do_single configs =
+  match configs with 
+  | [] -> raise (Sys_error "Too few arguments for action single")
+  | (Config c)::[] ->
+    let m = create_config (Config c) in
+    print_config m
+  | _::[] -> raise (Sys_error "Only config file supported for action single")
+  | _ -> raise (Sys_error "Too many arguments for action single")
+
+let do_create configs = 
+  match configs with 
+  | [] -> raise (Sys_error "Too few arguments for action create")
+  | (Config c)::[] -> raise (Sys_error "config file not supported for action create")
+  | (Subarch (a,s,f))::[] ->
+    let m = create_config (Subarch (a,s,f)) in 
+    print_config m
+  | (Flavour (a,f))::[] ->
+    let m = create_config (Flavour (a,f)) in 
+    print_config m
+  | _ -> raise (Sys_error "Too many arguments for action create")
+
+let do_check configs = 
+  match configs with 
+  | [] -> 
+    begin if !verbose then Printf.eprintf "Checking config files in %s\n" !basedir end;
+    let m = parse_defines_file (!basedir ^ "/defines") [] true in
+    print_defines m
+  | _ -> raise (Sys_error "Too many arguments for action check")
+
+let do_diff configs =
+  match configs with 
+  | [] | _::[] -> raise (Sys_error "Too few arguments for action diff")
+  | a::b::[] -> 
+    let ma = create_config a in
+    let mb = create_config b in
+    let d = diff_configs ma mb in
+    print_diff d
+  | _ -> raise (Sys_error "Too many arguments for action check")
+
+let print_error s = Printf.eprintf "Error:\n\n  %s\n\n" s; usage ()
 
 let () = try 
+    let () = Arg.parse spec set_action usage_string in
+    let configs : config list = config_of_temp (List.rev !temp) in
     match !action with
-    | Single -> do_single ()
-    | Create -> do_create ()
-    | Check -> do_check ()
-  with Sys_error s -> Printf.eprintf "Error: %s\n" s; usage ()
+    | Single -> do_single configs
+    | Create -> do_create configs
+    | Check -> do_check configs
+    | Diff -> do_diff configs
+    | NoAction -> print_error "no action provided"
+    | Help -> usage ()
+  with
+    | Sys_error s -> print_error s
+    | Bad_args s -> print_error (Printf.sprintf "while parsing args at \"%s\"" s)
+    | Bad_action s -> print_error (Printf.sprintf "unrecognized action \"%s\"" s)
+    | Double_action s ->print_error (Printf.sprintf "only one action allowed \"%s\"" s)
+
+(* 
+ * TODO items
+ *
+ *   full parsing of defines.
+ *   parsing of kernel kbuild tree.
+ *   parsing of kernel/module Makefiles.
+ *   generation of module description files.
+ *
+ *   organisation of kernels in a per-version, per-arch/subarch/flavour way in the archive.
+ *   (outside of the normal udeb/deb stable/testing/unstable/experimental archive).
+ *   Linking into the normal distributions, out of this alternate archive.
+ *   Implications for the archive tools : new upload queues.
+ *)



More information about the Kernel-svn-changes mailing list