4 # © 2013 Heiko Schlittermann <hs@schlittermann.de> |
4 # © 2013 Heiko Schlittermann <hs@schlittermann.de> |
5 |
5 |
6 use 5.010; |
6 use 5.010; |
7 use strict; |
7 use strict; |
8 use warnings; |
8 use warnings; |
|
9 use if $ENV{DEBUG} => 'Smart::Comments'; |
9 use English qw(-no_match_vars); |
10 use English qw(-no_match_vars); |
10 use File::Temp; |
11 use File::Temp; |
|
12 use File::Spec::Functions; |
|
13 use Getopt::Long; |
|
14 use Pod::Usage; |
11 |
15 |
12 our $VERSION = 0.01; |
16 our $VERSION = 0.01; |
13 |
17 |
14 my $CORE = '/etc/ldap/schema/core.schema'; |
18 my @opt_schema_dirs = qw(/etc/ldap/schema); |
|
19 my @opt_additional_schemas = (); |
15 |
20 |
16 die "$PROGRAM_NAME: $CORE: $!\n" if not -r $CORE; |
21 GetOptions( |
17 die "Need schema file\n" if not @ARGV == 1; |
22 'schema_dir=s@' => \@opt_schema_dirs, |
|
23 'additional_schema=s@' => \@opt_additional_schemas, |
|
24 ) and @ARGV == 1 or pod2usage(); |
|
25 |
|
26 # find the additional schema definitions |
|
27 my @schemas = do { |
|
28 my @rc = (); |
|
29 |
|
30 open(my $f, '<', $ARGV[0]) or die "$PROGRAM_NAME: $ARGV[0]: $!\n"; |
|
31 while (<$f>) { |
|
32 if (/^#schema2ldif:include\s+(\S+)/) { |
|
33 push @opt_additional_schemas, $1; |
|
34 } |
|
35 } |
|
36 close($f); |
|
37 foreach my $file (@opt_additional_schemas) { |
|
38 $file .= '.schema' unless $file =~ /\.schema$/xms; |
|
39 if (-f $file) { |
|
40 push @rc, catfile('.', $file); |
|
41 next; |
|
42 } |
|
43 ($_) = grep { -f } map { catfile $_, $file } @opt_schema_dirs; |
|
44 if ($_) { |
|
45 push @rc, $_; |
|
46 next; |
|
47 } |
|
48 die "$PROGRAM_NAME: $file: $!\n"; |
|
49 } |
|
50 @rc; |
|
51 }; |
|
52 |
|
53 ### @opt_schema_dirs |
|
54 ### @opt_additional_schemas |
|
55 ### @schemas |
18 |
56 |
19 (my $name = $ARGV[0]) =~ s/\.schema$//xms; |
57 (my $name = $ARGV[0]) =~ s/\.schema$//xms; |
20 my $cf = File::Temp->new(); |
58 my $cf = File::Temp->new(); |
21 my $cd = File::Temp->newdir(); |
59 my $cd = File::Temp->newdir(); |
22 |
60 |
23 # create a short temp config |
61 # create a short temp config |
24 $cf->print(<<"_EOF"); |
62 $cf->print("include $_\n") foreach @schemas, $ARGV[0]; |
25 include $CORE |
|
26 include $ARGV[0] |
|
27 _EOF |
|
28 close $cf or die "Can't close $cf: $!\n"; |
63 close $cf or die "Can't close $cf: $!\n"; |
29 # ... convert it |
64 # ... convert it |
30 system slaptest => ( -f => $cf ), |
65 system slaptest => ( -f => $cf ), |
31 ( -F => $cd ); |
66 ( -F => $cd ); |
|
67 die "slaptest failed, exit\n" if $?; |
32 |
68 |
33 # slurp the generated file |
69 # slurp the generated file |
|
70 # FIXME: what, if we had multiple preconditions |
34 open(my $ldif, '<', $_ = "$cd/cn=config/cn=schema/cn={1}$name.ldif") |
71 open(my $ldif, '<', $_ = "$cd/cn=config/cn=schema/cn={1}$name.ldif") |
35 or die "Can't open $_: $!\n"; |
72 or die "Can't open $_: $!\n"; |
36 $_ = do { local $RS = undef; <$ldif> }; |
73 $_ = do { local $RS = undef; <$ldif> }; |
37 close($ldif) or die "Can't close ldif generated ldif file: $!\n"; |
74 close($ldif) or die "Can't close ldif generated ldif file: $!\n"; |
38 |
75 |
45 print <<"__", $_; |
82 print <<"__", $_; |
46 # autogenerated by $PROGRAM_NAME |
83 # autogenerated by $PROGRAM_NAME |
47 # do not edit, edit $name.schema instead |
84 # do not edit, edit $name.schema instead |
48 # see https://ssl.schlittermann.de/hg/exim-ldap-schema |
85 # see https://ssl.schlittermann.de/hg/exim-ldap-schema |
49 __ |
86 __ |
|
87 |
|
88 __END__ |
|
89 |
|
90 =head1 NAME |
|
91 |
|
92 schema2ldif - convert an LDAP schema definition into an LDIF for cn=config |
|
93 |
|
94 =head1 SYNOPSIS |
|
95 |
|
96 schema2ldif [--schema-dir=s]... [--additional-schema=s]... schema |
|
97 |
|
98 =head1 DESCRIPTION |
|
99 |
|
100 This B<schema2ldif> converts an LDAP schema definition into an LDIF |
|
101 file. |
|
102 |
|
103 =head2 OPTIONS |
|
104 |
|
105 =over 4 |
|
106 |
|
107 =item B<--schema-dir> I<dir> |
|
108 |
|
109 A directory where to search for the additional schema(s). May |
|
110 be used multiple times. (default: F</etc/ldap/schemas> |
|
111 |
|
112 =item B<--additional-schema> I<schema> |
|
113 |
|
114 Additional schema to be included (preconditions for your self |
|
115 defind schema). The F<.schema> extension may be omitted. First it's |
|
116 searched in the local directory, then in the directories given in |
|
117 B<--schema-dir> option(s). (default: none) |
|
118 |
|
119 NOTE: A pseudo comment |
|
120 |
|
121 #include core.schema |
|
122 |
|
123 may be included in the schema to convert. It works the same way. |
|
124 |
|
125 |