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

Last change on this file since 68 was 68, checked in by nanardon, 15 years ago
  • more attributes supported
  • Property svn:keywords set to Id Rev
File size: 6.4 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 _traverse {
102    my ($self, $attr_cb, %options) = @_;
103   
104    # listing existing obj one time:
105    foreach my $otype ($self->from->list_supported_objects) {
106       
107        # If no dest support $otype, we skip
108        my @obj_dest_base = grep {
109            $_->is_supported_object($otype)
110        } $self->to or next;
111
112        # loading object list one time for all
113        # TODO optimize this, using rev of objects
114
115        warn "Sync objects $otype\n";
116        foreach my $destbase (@obj_dest_base) {
117            my @lobjfrom = $self->from->list_objects_from_rev(
118                $otype,
119                $self->val($self->from->label, $destbase->label),
120            );
121            warn "objects $otype " . $self->from->label . " => " . $destbase->label . "\n";
122            my @common_fields = $attr_cb->($self->from, $destbase, $otype) or next;
123            warn "Synching fields: " . join(', ', sort @common_fields) . "\n";
124            my %exists = map { $_ => 1 } $destbase->list_objects($otype);
125            foreach my $uid (@lobjfrom) {
126                my $sobj = $self->from->get_object($otype, $uid);
127                if ($exists{$uid}) {
128                    my %fields = map { $_ => $sobj->get_c_field($_, 'r') } @common_fields;
129                    my $dobj = $destbase->get_object($otype, $uid);
130                    $dobj->set_c_fields(%fields) unless($options{test});
131                    warn "  $otype $uid: synched\n";
132                } elsif (!$options{nocreate}) {
133                    my %fields = map { $_ => $sobj->get_c_field($_, 'r') } @common_fields;
134                    $destbase->create_c_object($otype, $uid, %fields) unless($options{test});
135                    warn "  $otype $uid: created\n";
136                }
137            }
138        }
139    }
140}
141
142sub process {
143    my ($self, %options) = @_;
144
145    $self->from->load or return;
146    # if any cannot be loaded, return,
147    # TODO we need a way to force if some still can be sync
148    $self->load_dest and return;
149   
150    # tracking current base revision:
151    $self->{current_rev} = $self->from->current_rev;
152
153    my %delayed;
154    $self->_traverse(
155        sub {
156            my ($from, $to, $otype) = @_;
157            my %fields = ();
158            my %delayed = map { $_ => 1 } $to->delayed_fields($otype);
159            foreach ($from->list_canonicals_fields($otype, 'r')) {
160                $delayed{$_} and next;
161                $fields{$_} ||= 0; # avoid
162                $fields{$_}++;
163            }
164            foreach ($to->list_canonicals_fields($otype, 'w')) {
165                $delayed{$_} and next;
166                $fields{$_} ||= 0; # avoid
167                $fields{$_}++;
168            }
169            # field having value are in both
170            grep { $fields{$_} == 2 } keys %fields;
171        },
172        %options
173    );
174    $self->_traverse(
175        sub {
176            my ($from, $to, $otype) = @_;
177            my %fields = ();
178            my %delayed = map { $_ => 1 } $to->delayed_fields($otype);
179            foreach ($from->list_canonicals_fields($otype, 'r')) {
180                $delayed{$_} and next;
181                $fields{$_} ||= 0; # avoid
182                $fields{$_}++;
183            }
184            foreach ($to->list_canonicals_fields($otype, 'w')) {
185                $delayed{$_} and next;
186                $fields{$_} ||= 0; # avoid
187                $fields{$_}++;
188            }
189            # field having value are in both
190            grep { $fields{$_} == 2 } keys %fields;
191        },
192        %options, nocreate => 1,
193    ) unless($options{nocreate} || $options{test});
194
195    foreach ($self->to) {
196        $_->commit or next;
197        $self->newval($self->from->label, $_->label, $self->{current_rev}) if($self->{current_rev});
198    }
199
200    $self->RewriteConfig if($self->GetFileName && !($options{nocreate} || $options{test}));
201   
202    1;
203}
204
2051;
206
207__END__
208# Below is stub documentation for your module. You'd better edit it!
209
210=head1 SEE ALSO
211
212Mention other useful documentation such as the documentation of
213related modules or operating system documentation (such as man pages
214in UNIX), or any relevant external documentation such as RFCs or
215standards.
216
217If you have a mailing list set up for your module, mention it here.
218
219If you have a web site set up for your module, mention it here.
220
221=head1 AUTHOR
222
223Thauvin Olivier, E<lt>olivier.thauvin@latmosipsl.frE<gt>
224
225=head1 COPYRIGHT AND LICENSE
226
227Copyright (C) 2009 by Thauvin Olivier
228
229This library is free software; you can redistribute it and/or modify
230it under the same terms as Perl itself, either Perl version 5.10.0 or,
231at your option, any later version of Perl 5 you may have available.
232
233
234=cut
Note: See TracBrowser for help on using the repository browser.