commit 9a7f1b6328d8f9529a200b342bac8d6296eb643e
Author: Marc Dequènes (Duck) <Duck@DuckCorp.org>
Date:   Thu Oct 22 23:38:37 2009 +0200

    [evol] added default config and simplified MilkyPond shadow config (and minor other changes)

diff --git a/conf/ldap_shadows/shadows/MilkyPond/aspects/ftp.conf b/conf/ldap_shadows/shadows/MilkyPond/aspects/ftp.conf
index a839e44..f0542a2 100644
--- a/conf/ldap_shadows/shadows/MilkyPond/aspects/ftp.conf
+++ b/conf/ldap_shadows/shadows/MilkyPond/aspects/ftp.conf
@@ -1,5 +1,3 @@
 mapping:
   classes: ['ftpUser']
   depend_aspects: ['primary', 'fs']
-presentation:
-relations:
diff --git a/conf/ldap_shadows/shadows/MilkyPond/aspects/jabber.conf b/conf/ldap_shadows/shadows/MilkyPond/aspects/jabber.conf
index 7124b08..388af61 100644
--- a/conf/ldap_shadows/shadows/MilkyPond/aspects/jabber.conf
+++ b/conf/ldap_shadows/shadows/MilkyPond/aspects/jabber.conf
@@ -1,4 +1,2 @@
 mapping:
   classes: ['jabberUser']
-presentation:
-relations:
diff --git a/conf/ldap_shadows/shadows/MilkyPond/aspects/mail.conf b/conf/ldap_shadows/shadows/MilkyPond/aspects/mail.conf
index f70e952..df7261e 100644
--- a/conf/ldap_shadows/shadows/MilkyPond/aspects/mail.conf
+++ b/conf/ldap_shadows/shadows/MilkyPond/aspects/mail.conf
@@ -1,4 +1,2 @@
 mapping:
   classes: ['emailUser']
-presentation:
-relations:
diff --git a/conf/ldap_shadows/shadows/MilkyPond/aspects/primary.conf b/conf/ldap_shadows/shadows/MilkyPond/aspects/primary.conf
index 3e737d7..a5cc429 100644
--- a/conf/ldap_shadows/shadows/MilkyPond/aspects/primary.conf
+++ b/conf/ldap_shadows/shadows/MilkyPond/aspects/primary.conf
@@ -2,4 +2,3 @@ mapping:
   classes: ['primaryAccount']
 presentation:
   associated_attributes: ['uid']
-relations:
diff --git a/conf/ldap_shadows/shadows/MilkyPond/aspects/shell.conf b/conf/ldap_shadows/shadows/MilkyPond/aspects/shell.conf
index e771450..ae83e20 100644
--- a/conf/ldap_shadows/shadows/MilkyPond/aspects/shell.conf
+++ b/conf/ldap_shadows/shadows/MilkyPond/aspects/shell.conf
@@ -3,4 +3,3 @@ mapping:
   depend_aspects: ['primary', 'fs']
 presentation:
   associated_attributes: ['loginShell']
-relations:
diff --git a/conf/ldap_shadows/shadows/MilkyPond/aspects/web.conf b/conf/ldap_shadows/shadows/MilkyPond/aspects/web.conf
index 19cb38b..8e43779 100644
--- a/conf/ldap_shadows/shadows/MilkyPond/aspects/web.conf
+++ b/conf/ldap_shadows/shadows/MilkyPond/aspects/web.conf
@@ -1,5 +1,3 @@
 mapping:
   classes: ['webUser']
   depend_aspects: ['primary']
-presentation:
-relations:
diff --git a/conf/ldap_shadows/shadows/MilkyPond/objects/domain.conf b/conf/ldap_shadows/shadows/MilkyPond/objects/domain.conf
index 4080849..5034883 100644
--- a/conf/ldap_shadows/shadows/MilkyPond/objects/domain.conf
+++ b/conf/ldap_shadows/shadows/MilkyPond/objects/domain.conf
@@ -3,5 +3,3 @@ mapping:
   prefix: ''
   classes: ['genericDomain']
   sort_by: cn
-presentation:
-  allowed_aspects: []
diff --git a/conf/ldap_shadows/shadows/MilkyPond/objects/group.conf b/conf/ldap_shadows/shadows/MilkyPond/objects/group.conf
index 0c57e39..57462d0 100644
--- a/conf/ldap_shadows/shadows/MilkyPond/objects/group.conf
+++ b/conf/ldap_shadows/shadows/MilkyPond/objects/group.conf
@@ -4,7 +4,6 @@ mapping:
   classes: ['posixGroup', 'groupOfMembers']
   sort_by: cn
 presentation:
-  allowed_aspects: []
   hidden_attributes: ['uniqueMember']
   expert_attributes: ['gidNumber']
   associated_relations: ['individualsPrimaryMembers', 'botsPrimaryMembers', 'individualsSecondaryMembers', 'botsSecondaryMembers']
diff --git a/data/ldap_shadows/default_config/aspect.yaml b/data/ldap_shadows/default_config/aspect.yaml
new file mode 100644
index 0000000..736a159
--- /dev/null
+++ b/data/ldap_shadows/default_config/aspect.yaml
@@ -0,0 +1,10 @@
+---
+mapping:
+  classes: []
+  depend_aspects: []
+presentation:
+  associated_attributes: []
+  associate_unclaimed_attributes: false
+  associated_relations: []
+relations: {}
+plugin: {}
diff --git a/data/ldap_shadows/default_config/global.yaml b/data/ldap_shadows/default_config/global.yaml
new file mode 100644
index 0000000..7cf158d
--- /dev/null
+++ b/data/ldap_shadows/default_config/global.yaml
@@ -0,0 +1,4 @@
+---
+default_shadow:
+password_hash:
+ldap: {}
diff --git a/data/ldap_shadows/default_config/object.yaml b/data/ldap_shadows/default_config/object.yaml
new file mode 100644
index 0000000..2e5a1f3
--- /dev/null
+++ b/data/ldap_shadows/default_config/object.yaml
@@ -0,0 +1,10 @@
+---
+mapping: {}
+presentation:
+  name_attribute:
+  allowed_aspects: []
+  hidden_attributes: []
+  expert_attributes: []
+  associated_relations: []
+relations: {}
+plugin: {}
diff --git a/data/ldap_shadows/default_config/shadow.yaml b/data/ldap_shadows/default_config/shadow.yaml
new file mode 100644
index 0000000..98718a1
--- /dev/null
+++ b/data/ldap_shadows/default_config/shadow.yaml
@@ -0,0 +1,4 @@
+---
+presentation:
+  hidden_attributes: []
+  tree_objects: []
diff --git a/lib/ldap_shadows/config.rb b/lib/ldap_shadows/config.rb
index ef93f8a..bf59279 100644
--- a/lib/ldap_shadows/config.rb
+++ b/lib/ldap_shadows/config.rb
@@ -20,6 +20,7 @@ require 'ldap_shadows/config_setup'
 require 'singleton'
 require 'yaml'
 require 'kwalify'
+require 'facets/hash/recursive_merge'
 require 'ldap_shadows/shadow'
 
 module LdapShadows
@@ -29,26 +30,30 @@ module LdapShadows
     def initialize
       @global_config = nil
       @schemas = {}
+      @default_configs = {}
       @shadows = {}
     end
 
     def load_global_config(extra_private_config_list = [])
+      g_default_config = load_default_config('global')
+
       g_config_file = File.join(CFG_DIR, "global.conf")
       unless File.exists? g_config_file
         raise PreProcessingError, _("Global LdapShadows config file is missing")
       end
 
-      g_config_partial = YAML.load_file(g_config_file) || {}
+      g_def_partial = YAML.load_file(g_config_file) || {}
       extra_private_config_list += [
         File.join(CFG_DIR, "global_private.conf")
         ]
       extra_private_config_list.each do |file|
         if File.exists?(file)
-          g_config_partial.merge!(YAML.load_file(file) || {})
+          g_def_partial.merge!(YAML.load_file(file) || {})
           break
         end
       end
-      g_config = parse_and_validate('config', 'global', YAML.dump(g_config_partial))
+      g_def = parse('config', 'global', YAML.dump(g_def_partial))
+      g_config = g_default_config.recursive_merge(g_def)
 
       ActiveLdap::Base.setup_connection(g_config[:ldap])
 
@@ -85,11 +90,11 @@ module LdapShadows
       }
       shadow.set_config(config)
 
-      load_config_components(shadow_config_path, 'aspects') do |c_name, c_config|
+      load_element_config(shadow_config_path, 'aspects') do |c_name, c_config|
         shadow.add_aspect(c_name, c_config)
       end
 
-      load_config_components(shadow_config_path, 'objects') do |c_name, c_config|
+      load_element_config(shadow_config_path, 'objects') do |c_name, c_config|
         shadow.add_object(c_name, c_config)
       end
 
@@ -111,20 +116,24 @@ module LdapShadows
       @shadows[shadow_name]
     end
 
-    def parse_and_validate(def_name, type, def_data_raw)
+    def parse(def_name, type, def_data_raw, validate = true)
       schema = load_schema(type)
 
-      validator_klass = case type
-      when 'global'
-        GlobalValidator
-      when 'object'
-        ObjectValidator
-      when 'aspect'
-        AspectValidator
+      if validate
+        validator_klass = case type
+        when 'global'
+          GlobalValidator
+        when 'object'
+          ObjectValidator
+        when 'aspect'
+          AspectValidator
+        else
+          Kwalify::Validator
+        end
+        validator = validator_klass.new(schema)
       else
-        Kwalify::Validator
+        validator = nil
       end
-      validator = validator_klass.new(schema)
 
       # validate config with schema
       parser = Kwalify::Yaml::Parser.new(validator)
@@ -134,6 +143,20 @@ module LdapShadows
       def_data.recursive_symbolize_keys!
     end
 
+    def load_default_config(type)
+      default_config = @default_configs[type]
+      if default_config.nil?
+        filename = File.join(DATA_DIR, "default_config", type + ".yaml")
+        default_config_raw = File.read(filename)
+        default_config = parse(':defaults:', type, default_config_raw, false)
+
+        @default_configs[type] = default_config
+      end
+      default_config
+    rescue
+      raise PreProcessingError, _("Could not load default config for '%s': %s") % [type, $!]
+    end
+
     def load_hook_content(shadow_name, type, hook_name)
       s_info = get_shadow_info(shadow_name)
       return nil if s_info.nil?
@@ -144,9 +167,7 @@ module LdapShadows
       File.read(filename)
     end
 
-    protected
-
-    def load_config_components(shadow_config_path, type)
+    def load_element_config(shadow_config_path, type)
       c_config_dir = File.join(shadow_config_path, type)
       c_config_pattern = File.join(c_config_dir, "**", "*.conf")
 
@@ -175,9 +196,11 @@ module LdapShadows
       end
       schema
     rescue
-      raise PreProcessingError, _("Could not load schema: %s") % $!
+      raise PreProcessingError, _("Could not load schema for '%s': %s") % [type, $!]
     end
 
+    protected
+
     def raise_if_validation_errors(name, errors)
       if errors and not errors.empty?
         err_msg = []
diff --git a/lib/ldap_shadows/shadow.rb b/lib/ldap_shadows/shadow.rb
index 1c28d1c..62ae075 100755
--- a/lib/ldap_shadows/shadow.rb
+++ b/lib/ldap_shadows/shadow.rb
@@ -48,7 +48,9 @@ module LdapShadows
     end
 
     def set_config(shadow_def_raw)
-      @shadow_config = @config.parse_and_validate(@name, 'shadow', shadow_def_raw)
+      shadow_default_config = @config.load_default_config('shadow')
+      shadow_def = @config.parse(@name, 'shadow', shadow_def_raw)
+      @shadow_config = shadow_default_config.recursive_merge(shadow_def)
     end
 
     def get_config
@@ -178,7 +180,9 @@ module LdapShadows
         raise PreProcessingError, _("Element '%s' for model '%s' as already been defined") % [e_name, e_type]
       end
 
-      e_def = @config.parse_and_validate(e_name, e_type, e_def_raw)
+      e_def = @config.parse(e_name, e_type, e_def_raw)
+      e_default_parameters = @config.load_default_config(e_type)
+      e_config = e_default_parameters.recursive_merge(e_def)
 
       klass = @container.module_eval(<<-EOS)
         class #{klass_name} < #{superklass_location}::#{superklass_name}; self; end
@@ -186,7 +190,7 @@ module LdapShadows
       klass.instance_variable_set(:@handle, e_name)
       klass.instance_variable_set(:@shadow, self)
       klass.instance_variable_set(:@config, @config)
-      klass.instance_variable_set(:@parameters, e_def)
+      klass.instance_variable_set(:@parameters, e_config)
       klass.meta_eval do
         attr_reader :handle, :shadow, :config, :parameters
       end
