my $split = $tcl->curry::weak::SplitList;
-my (@res, @last_q);
+my ($r, $res, @last_q);
-sub do_query {
- @res = $solver->query(@last_q)->results;
- Dwarn([ map {
+my $last_mode;
+
+sub show {
+ $r = ($res->isa('DX::Result') ? $res : $res->next);
+ unless ($r) { warn "false\n"; return; }
+ Dwarn(map {
my @act = $_->actions;
((@act ? \@act : ()), $_->all_values);
- } @res ]);
+ } $r);
+}
+
+sub do_query {
+ $res = $solver->$last_mode(@last_q);
+ show();
}
sub expand_def {
}
sub expand_body {
- my ($body) = @_;
+ my (@body) = @_;
local our @Body_Parts;
- $tcl->Eval($body);
+ $tcl->Eval(@body);
return @Body_Parts;
}
-$tcl->CreateCommand(query => sub {
- my (undef, undef, undef, $body) = @_;
- @last_q = expand_body($body);
+sub q_command {
+ my ($this_mode, undef, undef, undef, $body) = @_;
+ $last_mode = $this_mode;
+ if ($body) {
+ @last_q = expand_body($body);
+ }
do_query();
return;
-});
+}
+
+$tcl->CreateCommand('?' => sub { q_command(query => @_) });
+$tcl->CreateCommand('?!' => sub { q_command(solve => @_) });
+$tcl->CreateCommand('!?' => sub { q_command(solve => @_) });
+$tcl->CreateCommand('!' => sub { q_command(ensure => @_) });
$tcl->CreateCommand(run => sub {
- foreach my $ind ($res[0]->independent_actions) {
- my $cl = ref($ind);
- warn +(split('::', $cl))[-1]."\n";
+ foreach my $ind ($r->independent_actions) {
$solver->run_action($ind);
}
do_query();
$tcl->CreateCommand(dump => sub {
my (undef, undef, undef, $to_dump) = @_;
my $filter = quote_sub($to_dump);
- Dwarn(map $filter->($_), @res);
+ Dwarn($filter->($r));
});
sub mangle_args {
];
return;
});
+
+$tcl->CreateCommand(findall => sub {
+ my (undef, undef, undef, $coll_var, $name_var, $body) = @_;
+ push our @Body_Parts, [
+ findall => $coll_var => $name_var => expand_body($body)
+ ];
+ return;
+});
#$tcl->Eval(q{query D {directory_at D 't'; mode D '0755'; }});
($state, my %args) = $self->_expand_args($state, %{$self->_arg_map});
my @vars = @args{sort keys %args};
return $state->backtrack unless @vars == grep $_->is_bound, @vars;
+ return $state->backtrack unless $state->allow_actions;
my @deps = $state->action_dependencies(map $_->id, @vars);
my $action = $self->builder->(map $state->resolve_value($_), @vars)
->but(dependencies => \@deps);
$state->then($op);
}
);
+ my $allow = $state->allow_actions;
my $ret = DX::Op::SetScope->new(
scope => $state->scope,
- next => $self->make_result_handler($coll),
+ next => DX::Op::FromCode->new(
+ code => sub {
+ my ($self, $state) = @_;
+ $state->but(allow_actions => $allow)
+ ->then($self->next);
+ },
+ next => $self->make_result_handler($coll),
+ )
);
$state->assign_vars($self->var_name => {})
+ ->but(allow_actions => 0)
->push_return_then($ret, $invoke)->mark_choice($var);
}
sub query {
my ($self, @terms) = @_;
+ $self->_solve({ allow_actions => 0 }, @terms);
+}
+
+sub solve {
+ my ($self, @terms) = @_;
+ $self->_solve({ allow_actions => 1 }, @terms);
+}
+
+sub ensure {
+ my ($self, @terms) = @_;
+ my $rs = $self->_solve({ allow_actions => 1 }, @terms);
+ my $r = $rs->next;
+ while ($r and $r->actions and my @ind = $r->independent_actions) {
+ $self->run_action($_) for @ind;
+ $rs = $self->_solve({ allow_actions => 1 }, @terms);
+ $r = $rs->next;
+ }
+ return $r;
+}
+
+sub _solve {
+ my ($self, $attrs, @terms) = @_;
my $rule_set = $self->rule_set;
my $head = $rule_set->expand_and_link(undef, @terms, [ 'materialize' ]);
my $state = DX::State->new(
last_choice => [],
facts => $self->facts,
rule_set => $rule_set,
+ %$attrs
);
return DX::ResultStream->new(
for_state => $state,
sub run_action {
my ($self, $action) = @_;
+ warn +(split('::', ref($action)))[-1]."\n";
my @invalidate = $action->run;
while (my ($type, $value) = splice @invalidate, 0, 2) {
$self->facts->{$type}->remove_value($value);
has dependencies => (is => 'ro', default => sub { {} });
+has allow_actions => (is => 'ro', default => sub { 1 });
+
has actions => (is => 'ro', default => sub { {} });
sub has_scope_var {
%path_status = %protos;
sub paths_for_simple {
- join ' ', map $_->value_for('PS')->path, $solver->query(
+ join ' ', map $_->value_for('PS')->path, $solver->solve(
[ path_status => 'PS' ], @_
)->results;
}
);
throws_ok {
- $solver->query(
+ $solver->solve(
[ path_status_at => 'PS', \'.ssh' ]
)->results
} qr/ARGH/;
my @res;
lives_ok {
- @res = $solver->query(
+ @res = $solver->solve(
[ path_status_at => 'PS', \'.ssh' ]
)->results
};
$ob_res{'.ssh'} = $protos{'.ssh'};
sub paths_for {
- join ' ', map $_->value_for('PS')->path, $solver->query(@_)->results;
+ join ' ', map $_->value_for('PS')->path, $solver->solve(@_)->results;
}
is(
$solver->{observation_policy} = sub { 1 };
sub dot_ssh_query {
- $solver->query([ directory_at => 'PS' => \'.ssh' ]);
+ $solver->solve([ directory_at => 'PS' => \'.ssh' ]);
}
is_deeply(
%ob_res = %empty;
sub keys_file {
- $solver->query(
+ $solver->solve(
[ directory_at => 'D' => \'.ssh' ],
[ file_in => 'D' => \'authorized_keys' => 'F' ],
);