Commit | Line | Data |
4d2ad771 |
1 | package DX::Lib::FS; |
2 | |
3 | use DX::Lib::FS::Observation::PathStatus; |
6a7c71ff |
4 | use DX::Lib::FS::Observation::EnvDir; |
4d2ad771 |
5 | use DX::Lib::FS::Action::CreateDirectory; |
6 | use DX::Lib::FS::Action::CreateFile; |
ae75ed8b |
7 | use DX::Lib::FS::Action::SetPathMode; |
8c3eab7b |
8 | use DX::Lib::FS::Observation::FileContent; |
9 | use DX::Lib::FS::Action::RewriteFile; |
4d2ad771 |
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' ] ], |
dd866f63 |
17 | |
18 | [ _path_status_at => [ qw(PS P) ], |
4d2ad771 |
19 | [ path_status => 'PS' ], |
dd866f63 |
20 | [ prop => PS => \'path' => 'P' ] ], |
21 | |
22 | [ path_status_at => [ qw(PS P) ], |
23 | [ _path_status_at => qw(PS P) ], |
4d2ad771 |
24 | [ 'cut' ] ], |
dd866f63 |
25 | |
4d2ad771 |
26 | [ path_status_at => [ 'PS', 'P' ], |
27 | [ observe => [ 'P' ], sub { |
28 | DX::Lib::FS::Observation::PathStatus->new( |
29 | path => $_[0] |
30 | ) |
31 | } ], |
dd866f63 |
32 | [ _path_status_at => qw(PS P) ] ], |
33 | |
34 | [ ps_prop => [ 'P', 'Name', 'Value' ], |
1ca2da5e |
35 | [ path_status_at => qw(PS P) ], |
36 | [ prop => qw(PS Name Value) ] ], |
dd866f63 |
37 | |
38 | [ ps_info_prop => [ 'P', 'Name', 'Value' ], |
1ca2da5e |
39 | [ ps_prop => 'P', \'info', 'PSI' ], |
40 | [ prop => 'PSI', 'Name', 'Value' ] ], |
dd866f63 |
41 | |
42 | [ exists_path => [ qw(P) ], |
1ca2da5e |
43 | [ ps_prop => 'P' => \'info' => 'PSI' ] ], |
dd866f63 |
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' ], |
6d531540 |
64 | [ not => [ [ _is_directory => 'Path' ] ] ], |
dd866f63 |
65 | [ act => [ 'Path' ], sub { |
4d2ad771 |
66 | DX::Lib::FS::Action::CreateDirectory->new( |
dd866f63 |
67 | path => $_[0], |
4d2ad771 |
68 | ) |
dd866f63 |
69 | } ], |
70 | [ _is_directory => 'Path' ] ], |
71 | |
72 | [ is_file => [ 'Path' ], |
6d531540 |
73 | [ not => [ [ _is_file => 'Path' ] ] ], |
dd866f63 |
74 | [ act => [ 'Path' ], sub { |
4d2ad771 |
75 | DX::Lib::FS::Action::CreateFile->new( |
dd866f63 |
76 | path => $_[0], |
4d2ad771 |
77 | ) |
dd866f63 |
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) ], |
1ca2da5e |
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 | } ], |
dd866f63 |
94 | [ 'cut' ] ], |
95 | |
96 | [ mode => [ qw(P M) ], |
1ca2da5e |
97 | [ path_status_at => qw(PS P) ], |
6d531540 |
98 | [ not => [ [ _mode => qw(P M) ] ] ], |
1ca2da5e |
99 | [ act => [ qw(PS M) ], sub { |
100 | DX::Lib::FS::Action::SetPathMode->new( |
101 | path_status => $_[0], mode => $_[1] |
102 | ) |
103 | } ], |
dd866f63 |
104 | [ 'cut' ] ], |
105 | |
8c3eab7b |
106 | [ file_content => [ qw(FC) ], |
107 | [ member_of => 'FC', \'file_content' ] ], |
dd866f63 |
108 | |
109 | [ _file_content_at => [ qw(FC P) ], |
8c3eab7b |
110 | [ file_content => 'FC' ], |
dd866f63 |
111 | [ prop => 'FC', \'path', 'P' ] ], |
112 | |
113 | [ file_content_at => [ qw(FC P) ], |
114 | [ _file_content_at => qw(FC P) ], |
8c3eab7b |
115 | [ 'cut' ] ], |
dd866f63 |
116 | |
8c3eab7b |
117 | [ file_content_at => [ qw(FC P) ], |
dd866f63 |
118 | [ is_file => 'P' ], |
8c3eab7b |
119 | [ observe => [ 'P' ], sub { |
120 | DX::Lib::FS::Observation::FileContent->new( |
121 | path => $_[0] |
122 | ) |
123 | } ], |
dd866f63 |
124 | [ _file_content_at => qw(FC P) ] ], |
125 | |
126 | [ fc_prop => [ qw(P Name Value) ], |
1ca2da5e |
127 | [ file_content_at => qw(FC P) ], |
128 | [ prop => qw(FC Name Value) ] ], |
dd866f63 |
129 | |
130 | [ file_data => [ qw(P D) ], [ fc_prop => 'P', \'data', 'D' ] ], |
131 | |
132 | [ _contains_line => [ qw(P L) ], |
133 | [ is_file => 'P' ], |
1ca2da5e |
134 | [ fc_prop => 'P', \'lines', 'Lines' ], |
135 | [ member_of => qw(L Lines) ] ], |
dd866f63 |
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) ], |
6d531540 |
147 | [ not => [ [ _contains_line => qw(P L) ] ] ], |
1ca2da5e |
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 | } ], |
8c3eab7b |
154 | [ 'cut' ] ], |
dd866f63 |
155 | |
156 | [ contains_line => [ qw(P L) ], |
6d531540 |
157 | [ not => [ [ _contains_line => qw(P L) ] ] ], |
1ca2da5e |
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 | } ] ], |
dd866f63 |
164 | |
165 | [ not_contains_line => [ qw(P L) ], |
6d531540 |
166 | [ not => [ [ _contains_line => qw(P L) ] ] ] ], |
dd866f63 |
167 | |
168 | [ _arrange_removal_of => [ qw(FC L) ], |
1ca2da5e |
169 | [ has_action => qw(FC A) ], |
170 | [ does => 'A' => \'DX::Lib::FS::Action::RewriteFile' ], |
dd866f63 |
171 | [ react => [ qw(FC L) ], sub { $_[0]->but_remove($_[1]) } ] ], |
172 | |
173 | [ _arrange_removal_of => [ qw(FC L) ], |
8c3eab7b |
174 | [ act => [ qw(FC L) ], sub { |
175 | DX::Lib::FS::Action::RewriteFile->new( |
176 | from => $_[0], |
dd866f63 |
177 | )->but_remove($_[1]); |
178 | } ] ], |
179 | |
180 | [ not_contains_line => [ qw(P L) ], |
181 | [ _contains_line => qw(P L) ], |
1ca2da5e |
182 | [ file_content_at => qw(FC P) ], |
183 | [ _arrange_removal_of => qw(FC L) ], |
8c3eab7b |
184 | [ 'cut' ] ], |
dd866f63 |
185 | |
186 | [ file_in => [ qw(DirPath FileName FilePath) ], |
187 | [ catfile => qw(DirPath FileName FilePath) ], |
188 | [ is_directory => 'DirPath' ], |
189 | [ is_file => 'FilePath' ] ], |
6a7c71ff |
190 | |
191 | [ directory_in => [ qw(DirPath DirName SubdirPath) ], |
10ccac75 |
192 | [ catdir => qw(DirPath DirName SubdirPath) ], |
6a7c71ff |
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 | |
faf8cdf0 |
215 | [ env_dir_on => [ qw(A E D) ], |
216 | [ path_on => 'A', 'E', 'P' ], |
6a7c71ff |
217 | [ env_dir_at => ED => 'P' ], |
218 | [ prop => ED => \'value' => 'H' ], |
219 | [ path_on => 'A', 'H', 'D' ] ], |
faf8cdf0 |
220 | |
221 | [ home_dir_on => [ qw(A D) ], |
222 | [ env_dir_on => 'A', \'HOME', 'D' ] ], |
4d2ad771 |
223 | ); |
224 | |
225 | sub load_into { |
226 | my ($self, $solver) = @_; |
227 | $solver->facts->{path_status} = DX::SetOver->new(over => 'path'); |
8c3eab7b |
228 | $solver->facts->{file_content} = DX::SetOver->new(over => 'path'); |
6a7c71ff |
229 | $solver->facts->{env_dir} = DX::SetOver->new(over => 'path'); |
4d2ad771 |
230 | $solver->add_predicate( |
231 | catdir => [ qw(DirPath DirName SubDirPath) ], |
232 | [ qw(+ + -) ] => sub { |
233 | +(SubDirPath => [ |
234 | value => File::Spec->catdir($_{DirPath}, $_{DirName}) |
235 | ]) |
236 | }, |
237 | [ qw(- - +) ] => sub { |
238 | my @split = File::Spec->splitdir($_{SubDirPath}); |
239 | my $last = pop @split; |
240 | my $rest = File::Spec->catdir(@split); |
241 | +(DirPath => [ value => $rest ], DirName => [ value => $last ]) |
242 | } |
243 | ); |
244 | $solver->add_predicate( |
245 | catfile => [ qw(DirPath FileName FilePath) ], |
246 | [ qw(+ + -) ] => sub { |
247 | my ($vol, $dir) = File::Spec->splitpath($_{DirPath}, 1); |
640fa37e |
248 | my $file_path = File::Spec->catpath($vol, $dir, $_{FileName}); |
4d2ad771 |
249 | +(FilePath => [ value => $file_path ]) |
250 | }, |
251 | [ qw(- - +) ] => sub { |
252 | my ($vol, $dir, $file) = File::Spec->splitpath($_{FilePath}); |
253 | my $dir_path = File::Spec->catpath($vol, $dir); |
254 | +(DirPath => [ value => $dir_path ], FileName => [ value => $file ]) |
255 | } |
256 | ); |
0d1a41d9 |
257 | $solver->add_predicate( |
258 | path_on => [ qw(On Path FullPath) ], |
259 | [ qw(+ + -) ] => sub { |
260 | (my $path = $_{Path}) =~ s/^(:!\/)/.\//; |
261 | if ($_{On} eq '' or $_{On} eq 'localhost') { |
262 | (FullPath => [ value => $path ]) |
263 | } else { |
264 | (FullPath => [ value => join(':', $_{On}, $path) ]) |
265 | } |
266 | }, |
267 | [ qw(- - +) ] => sub { |
268 | if (my ($on, $path) = $_{FullPath} =~ /^([^\/]+):(.*)$/) { |
269 | (On => [ value => $on ], Path => [ value => $path ]); |
270 | } else { |
271 | (On => [ value => 'localhost' ], Path => [ value => $_{FullPath} ]); |
272 | } |
273 | } |
274 | ); |
640fa37e |
275 | $solver->add_rule( |
276 | does => [ qw(Thing RoleName) ], |
277 | [ constrain => [ qw(Thing RoleName) ], sub { $_[0]->DOES($_[1]) } ] |
278 | ); |
4d2ad771 |
279 | $solver->add_rule(@$_) for @RULES; |
280 | } |
281 | |
282 | 1; |