source: LATMOS-Accounts/lib/LATMOS/Accounts/Synchro.pm @ 60

Last change on this file since 60 was 60, checked in by nanardon, 15 years ago
  • permform synchronisation in two step, second pass is done for fileds having foreign key constrait such user <=> group link
  • Property svn:keywords set to Id Rev
File size: 6.2 KB
Line 
1package LATMOS::Accounts::Synchro;
2
3use 5.010000;
4use strict;
5use warnings;
6use base qw(Config::IniFiles);
7use LATMOS::Accounts::Bases;
8
9=head1 NAME
10
11LATMOS::Accounts::Synchro - Perl extension for blah blah blah
12
13=head1 SYNOPSIS
14
15  use LATMOS::Accounts;
16  blah blah blah
17
18=head1 DESCRIPTION
19
20Stub documentation for LATMOS::Accounts, created by h2xs. It looks like the
21author of the extension was negligent enough to leave the stub
22unedited.
23
24Blah blah blah.
25
26=head1 FUNCTIONS
27
28=cut
29
30our $VERSION = (q$Rev$ =~ /^Rev: (\d+) /)[0];
31
32=head2 new($from, $to, %options)
33
34Create a new synchronisation where $from and $to are LATMOS::Accounts::Base
35based objects. $to can be an array ref of objects.
36
37=cut
38
39sub new {
40    my ($class, $from, $to, %options) = @_;
41
42    if ($options{state_file} && ! -w $options{state_file}) {
43        # don't exists, we have to create it
44        open(my $handle, '>', $options{state_file}) or return;
45        print $handle "[_default_]\n";
46        close($handle);
47    }
48
49    my $self = Config::IniFiles->new(
50        $options{state_file}
51        ? (-file => $options{state_file})
52        : (),
53    );
54
55    if ($options{state_file} && !$self->GetFileName) {
56        $self->SetFileName($options{state_file});
57    }
58   
59    $self->{from} = $from;
60
61    # allow ref and array ref of, eg
62    # to = $foo and $to = [ $foo, $bar ]
63    foreach (ref($to) eq 'ARRAY' ? @{ $to || []} : ($to)) {
64        push(@{$self->{to}}, $_);
65    }
66    bless($self, $class)
67}
68
69sub from {
70    my ($self) = @_;
71    return $self->{from}
72}
73
74sub to {
75    my ($self) = @_;
76    return @{$self->{to} || []};
77}
78
79=head2 load_dest
80
81Try to loaded all base, return the count of filtrered base which cannot
82be loaded
83
84=cut
85
86sub load_dest {
87    my ($self) = @_;
88    my @loaded;
89    my $unloaded = 0;
90    foreach ($self->to) {
91        if($_->load) {
92            push(@loaded, $_);
93        } else {
94            $unloaded++;
95        }
96    }
97    $self->{to} = \@loaded;
98    return $unloaded;
99}
100
101sub _common_fields {
102    my ($self, $from, $to, $otype) = @_;
103    my %fields = ();
104    foreach my $base ($from, $to) {
105        foreach ($base->list_canonicals_fields($otype)) {
106            $fields{$_} ||= 0; # avoid
107            $fields{$_}++;
108        }
109    }
110    # field having value are in both
111    grep { $fields{$_} == 2 } keys %fields;
112}
113
114sub _traverse {
115    my ($self, $attr_cb, %options) = @_;
116   
117    # listing existing obj one time:
118    foreach my $otype ($self->from->list_supported_objects) {
119       
120        # If no dest support $otype, we skip
121        my @obj_dest_base = grep {
122            $_->is_supported_object($otype)
123        } $self->to or next;
124
125        # loading object list one time for all
126        # TODO optimize this, using rev of objects
127
128        warn "Sync objects $otype\n";
129        foreach my $destbase (@obj_dest_base) {
130            my @lobjfrom = $self->from->list_objects_from_rev(
131                $otype,
132                $self->val($self->from->label, $destbase->label),
133            );
134            warn "objects $otype => " . $destbase->type . "\n";
135            my @common_fields = $attr_cb->($self->from, $destbase, $otype) or next;
136            my %exists = map { $_ => 1 } $destbase->list_objects($otype);
137            foreach my $uid (@lobjfrom) {
138                my $sobj = $self->from->get_object($otype, $uid);
139                my %fields = map { $_ => $sobj->get_c_field($_, 'r') } @common_fields;
140                if (!$exists{$uid}) {
141                    $destbase->create_c_object($otype, $uid, %fields);
142                    warn "  $otype $uid: created\n";
143                } else {
144                    my $dobj = $destbase->get_object($otype, $uid);
145                    $dobj->set_c_fields(%fields);
146                    warn "  $otype $uid: synched\n";
147                }
148            }
149        }
150    }
151}
152
153sub process {
154    my ($self, %options) = @_;
155
156    $self->from->load or return;
157    # if any cannot be loaded, return,
158    # TODO we need a way to force if some still can be sync
159    $self->load_dest and return;
160   
161    # tracking current base revision:
162    $self->{current_rev} = $self->from->current_rev;
163
164    my %delayed;
165    $self->_traverse(
166        sub {
167            my ($from, $to, $otype) = @_;
168            my %fields = ();
169            my %delayed = map { $_ => 1 } $to->delayed_fields($otype);
170            foreach my $base ($from, $to) {
171                foreach ($base->list_canonicals_fields($otype)) {
172                    $delayed{$_} and next;
173                    $fields{$_} ||= 0; # avoid
174                    $fields{$_}++;
175                }
176            }
177            # field having value are in both
178            grep { $fields{$_} == 2 } keys %fields;
179        },
180        %options
181    );
182    $self->_traverse(
183        sub {
184            my ($from, $to, $otype) = @_;
185            my %fields = ();
186            my %delayed = map { $_ => 1 } $to->delayed_fields($otype);
187            foreach my $base ($from, $to) {
188                foreach ($base->list_canonicals_fields($otype)) {
189                    $delayed{$_} or next;
190                    $fields{$_} ||= 0; # avoid
191                    $fields{$_}++;
192                }
193            }
194            # field having value are in both
195            grep { $fields{$_} == 2 } keys %fields;
196        },
197        %options
198    );
199
200    foreach ($self->to) {
201        $_->commit or next;
202        $self->newval($self->from->label, $_->label, $self->{current_rev}) if($self->{current_rev});
203    }
204
205    $self->RewriteConfig if($self->GetFileName);
206   
207    1;
208}
209
2101;
211
212__END__
213# Below is stub documentation for your module. You'd better edit it!
214
215=head1 SEE ALSO
216
217Mention other useful documentation such as the documentation of
218related modules or operating system documentation (such as man pages
219in UNIX), or any relevant external documentation such as RFCs or
220standards.
221
222If you have a mailing list set up for your module, mention it here.
223
224If you have a web site set up for your module, mention it here.
225
226=head1 AUTHOR
227
228Thauvin Olivier, E<lt>olivier.thauvin@latmosipsl.frE<gt>
229
230=head1 COPYRIGHT AND LICENSE
231
232Copyright (C) 2009 by Thauvin Olivier
233
234This library is free software; you can redistribute it and/or modify
235it under the same terms as Perl itself, either Perl version 5.10.0 or,
236at your option, any later version of Perl 5 you may have available.
237
238
239=cut
Note: See TracBrowser for help on using the repository browser.