0e2b51b518aa6690306be4711906717cd39e76a6
[scpubgit/DKit.git] / lib / DX / Lib / FS.pm
1 package DX::Lib::FS;
2
3 use DX::Lib::FS::Observation::PathStatus;
4 use DX::Lib::FS::Observation::EnvDir;
5 use DX::Lib::FS::Action::CreateDirectory;
6 use DX::Lib::FS::Action::CreateFile;
7 use DX::Lib::FS::Action::SetPathMode;
8 use DX::Lib::FS::Observation::FileContent;
9 use DX::Lib::FS::Action::RewriteFile;
10 use File::Spec;
11 use DX::SetOver;
12 use Moo;
13
14 our @RULES = (
15   [ path_status => [ qw(PS) ],
16     [ member_of => 'PS', \'path_status' ] ],
17
18   [ _path_status_at => [ qw(PS P) ],
19     [ path_status => 'PS' ],
20     [ prop => PS => \'path' => 'P' ] ],
21
22   [ path_status_at => [ qw(PS P) ],
23     [ _path_status_at => qw(PS P) ],
24     [ 'cut' ] ],
25
26   [ path_status_at => [ 'PS', 'P' ],
27     [ observe => [ 'P' ], sub {
28         DX::Lib::FS::Observation::PathStatus->new(
29           path => $_[0]
30         )
31       } ],
32     [ _path_status_at => qw(PS P) ] ],
33
34   [ ps_prop => [ 'P', 'Name', 'Value' ],
35     [ path_status_at => qw(PS P) ],
36     [ prop => qw(PS Name Value) ] ],
37
38   [ ps_info_prop => [ 'P', 'Name', 'Value' ],
39     [ ps_prop => 'P', \'info', 'PSI' ],
40     [ prop => 'PSI', 'Name', 'Value' ] ],
41
42   [ exists_path => [ qw(P) ],
43     [ ps_prop => 'P' => \'info' => 'PSI' ] ],
44
45   [ _is_directory => [ qw(P) ],
46     [ ps_info_prop => 'P' => \'is_directory' => \1 ] ],
47
48   [ is_directory => [ qw(P) ],
49     [ _is_directory => 'P' ] ],
50
51   [ _is_file => [ qw(P) ],
52     [ ps_info_prop => 'P' => \'is_file' => \1 ] ],
53
54   [ is_file => [ qw(P) ],
55     [ _is_file => 'P' ] ],
56
57   [ _mode => [ qw(P M) ],
58     [ ps_info_prop => 'P' => \'mode' => 'M' ] ],
59
60   [ mode => [ qw(P M) ],
61     [ _mode => qw(P M) ] ],
62
63   [ is_directory => [ 'Path' ],
64     [ not => [ _is_directory => 'Path' ] ],
65     [ act => [ 'Path' ], sub {
66         DX::Lib::FS::Action::CreateDirectory->new(
67           path => $_[0],
68         )
69       } ],
70     [ _is_directory => 'Path' ] ],
71
72   [ is_file => [ 'Path' ],
73     [ not => [ _is_file => 'Path' ] ],
74     [ act => [ 'Path' ], sub {
75         DX::Lib::FS::Action::CreateFile->new(
76           path => $_[0],
77         )
78       } ],
79     [ _is_file => 'Path' ] ],
80
81   [ _action_is_creating => [ qw(A) ],
82     [ does => 'A', \'DX::Lib::FS::Action::CreateDirectory' ] ],
83
84   [ _action_is_creating => [ qw(A) ],
85     [ does => 'A', \'DX::Lib::FS::Action::CreateFile' ] ],
86     
87   [ mode => [ qw(P M) ],
88     [ path_status_at => qw(PS P) ],
89     [ has_action => qw(PS A) ],
90     [ _action_is_creating => 'A' ],
91     [ react => [ qw(PS M) ], sub {
92         $_[0]->but(mode => $_[1]);
93       } ],
94     [ 'cut' ] ],
95
96   [ mode => [ qw(P M) ],
97     [ path_status_at => qw(PS P) ],
98     [ not => [ _mode => qw(P M) ] ],
99     [ act => [ qw(PS M) ], sub {
100        DX::Lib::FS::Action::SetPathMode->new(
101          path_status => $_[0], mode => $_[1]
102        )
103     } ],
104     [ 'cut' ] ],
105
106   [ file_content => [ qw(FC) ],
107     [ member_of => 'FC', \'file_content' ] ],
108
109   [ _file_content_at => [ qw(FC P) ],
110     [ file_content => 'FC' ],
111     [ prop => 'FC', \'path', 'P' ] ],
112
113   [ file_content_at => [ qw(FC P) ],
114     [ _file_content_at => qw(FC P) ],
115     [ 'cut' ] ],
116
117   [ file_content_at => [ qw(FC P) ],
118     [ is_file => 'P' ],
119     [ observe => [ 'P' ], sub {
120         DX::Lib::FS::Observation::FileContent->new(
121           path => $_[0]
122         )
123       } ],
124     [ _file_content_at => qw(FC P) ] ],
125
126   [ fc_prop => [ qw(P Name Value) ],
127     [ file_content_at => qw(FC P) ],
128     [ prop => qw(FC Name Value) ] ],
129
130   [ file_data => [ qw(P D) ], [ fc_prop => 'P', \'data', 'D' ] ],
131
132   [ _contains_line => [ qw(P L) ],
133     [ is_file => 'P' ],
134     [ fc_prop => 'P', \'lines', 'Lines' ],
135     [ member_of => qw(L Lines) ] ],
136
137   [ contains_line => [ qw(P L) ],
138     [ _contains_line => qw(P L) ] ],
139
140   [ _action_modifying_fc => [ 'A' ],
141     [ does => 'A' => \'DX::Lib::FS::Action::CreateFile' ] ],
142
143   [ _action_modifying_fc => [ 'A' ],
144     [ does => 'A' => \'DX::Lib::FS::Action::RewriteFile' ] ],
145
146   [ contains_line => [ qw(P L) ],
147     [ not => [ _contains_line => qw(P L) ] ],
148     [ file_content_at => qw(FC P) ],
149     [ has_action => qw(FC A) ],
150     [ _action_modifying_fc => 'A' ],
151     [ react => [ qw(FC L) ], sub {
152         $_[0]->but_add($_[1])
153       } ],
154     [ 'cut' ] ],
155
156   [ contains_line => [ qw(P L) ],
157     [ not => [ _contains_line => qw(P L) ] ],
158     [ file_content_at => qw(FC P) ],
159     [ act => [ qw(FC L) ], sub {
160       DX::Lib::FS::Action::RewriteFile->new(
161         from => $_[0],
162       )->but_add($_[1])
163     } ] ],
164
165   [ not_contains_line => [ qw(P L) ],
166     [ not => [ _contains_line => qw(P L) ] ] ],
167
168   [ _arrange_removal_of => [ qw(FC L) ],
169     [ has_action => qw(FC A) ],
170     [ does => 'A' => \'DX::Lib::FS::Action::RewriteFile' ],
171     [ react => [ qw(FC L) ], sub { $_[0]->but_remove($_[1]) } ] ],
172
173   [ _arrange_removal_of => [ qw(FC L) ],
174     [ act => [ qw(FC L) ], sub {
175         DX::Lib::FS::Action::RewriteFile->new(
176           from => $_[0],
177         )->but_remove($_[1]);
178       } ] ],
179
180   [ not_contains_line => [ qw(P L) ],
181     [ _contains_line => qw(P L) ],
182     [ file_content_at => qw(FC P) ],
183     [ _arrange_removal_of => qw(FC L) ],
184     [ 'cut' ] ],
185
186   [ file_in => [ qw(DirPath FileName FilePath) ],
187     [ catfile => qw(DirPath FileName FilePath) ],
188     [ is_directory => 'DirPath' ],
189     [ is_file => 'FilePath' ] ],
190
191   [ directory_in => [ qw(DirPath DirName SubdirPath) ],
192     [ catfile => qw(DirPath DirName SubdirPath) ],
193     [ is_directory => 'DirPath' ],
194     [ is_directory => 'SubdirPath' ] ],
195
196   [ env_dir => [ qw(ED) ],
197     [ member_of => 'ED', \'env_dir' ] ],
198
199   [ _env_dir_at => [ qw(ED P) ],
200     [ env_dir => 'ED' ],
201     [ prop => ED => \'path' => 'P' ] ],
202
203   [ env_dir_at => [ qw(ED P) ],
204     [ _env_dir_at => qw(ED P) ],
205     [ 'cut' ] ],
206
207   [ env_dir_at => [ 'ED', 'P' ],
208     [ observe => [ 'P' ], sub {
209         DX::Lib::FS::Observation::EnvDir->new(
210           path => $_[0]
211         )
212       } ],
213     [ _env_dir_at => qw(ED P) ] ],
214
215   [ home_dir_on => [ qw(A D) ],
216     [ path_on => 'A', \'HOME', 'P' ],
217     [ env_dir_at => ED => 'P' ],
218     [ prop => ED => \'value' => 'H' ],
219     [ path_on => 'A', 'H', 'D' ] ],
220 );
221
222 sub load_into {
223   my ($self, $solver) = @_;
224   $solver->facts->{path_status} = DX::SetOver->new(over => 'path');
225   $solver->facts->{file_content} = DX::SetOver->new(over => 'path');
226   $solver->facts->{env_dir} = DX::SetOver->new(over => 'path');
227   $solver->add_predicate(
228     catdir => [ qw(DirPath DirName SubDirPath) ],
229       [ qw(+ + -) ] => sub {
230         +(SubDirPath => [
231            value => File::Spec->catdir($_{DirPath}, $_{DirName})
232         ])
233       },
234       [ qw(- - +) ] => sub {
235         my @split = File::Spec->splitdir($_{SubDirPath});
236         my $last = pop @split;
237         my $rest = File::Spec->catdir(@split);
238         +(DirPath => [ value => $rest ], DirName => [ value => $last ])
239       }
240   );
241   $solver->add_predicate(
242     catfile => [ qw(DirPath FileName FilePath) ],
243       [ qw(+ + -) ] => sub {
244         my ($vol, $dir) = File::Spec->splitpath($_{DirPath}, 1);
245         my $file_path = File::Spec->catpath($vol, $dir, $_{FileName});
246         +(FilePath => [ value => $file_path ])
247       },
248       [ qw(- - +) ] => sub {
249         my ($vol, $dir, $file) = File::Spec->splitpath($_{FilePath});
250         my $dir_path = File::Spec->catpath($vol, $dir);
251         +(DirPath => [ value => $dir_path ], FileName => [ value => $file ])
252       }
253   );
254   $solver->add_predicate(
255     path_on => [ qw(On Path FullPath) ],
256       [ qw(+ + -) ] => sub {
257         (my $path = $_{Path}) =~ s/^(:!\/)/.\//;
258         if ($_{On} eq '' or $_{On} eq 'localhost') {
259           (FullPath => [ value => $path ])
260         } else {
261           (FullPath => [ value => join(':', $_{On}, $path) ])
262         }
263       },
264       [ qw(- - +) ] => sub {
265         if (my ($on, $path) = $_{FullPath} =~ /^([^\/]+):(.*)$/) {
266           (On => [ value => $on ], Path => [ value => $path ]);
267         } else {
268           (On => [ value => 'localhost' ], Path => [ value => $_{FullPath} ]);
269         }
270       }
271   );
272   $solver->add_rule(
273     does => [ qw(Thing RoleName) ],
274       [ constrain => [ qw(Thing RoleName) ], sub { $_[0]->DOES($_[1]) } ]
275   );
276   $solver->add_rule(@$_) for @RULES;
277 }
278
279 1;