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