Skip to content

Commit

Permalink
Add --step-on-block/--step option to solver (#1017)
Browse files Browse the repository at this point in the history
This pauses the solver when a BLOCKED state is reached (a step-back
change). The solver will start up again when the user hits Enter.
---------

Signed-off-by: David Gilligan-Cook <dcook@imageworks.com>
  • Loading branch information
dcookspi authored May 31, 2024
1 parent e90d9b5 commit 506cd85
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 23 deletions.
5 changes: 5 additions & 0 deletions crates/spk-cli/common/src/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1082,6 +1082,10 @@ pub struct DecisionFormatterSettings {
/// Stop the solver the first time it is BLOCKED.
#[clap(long, alias = "stop")]
stop_on_block: bool,

/// Pause the solver each time it is blocked, until the user hits Enter.
#[clap(long, alias = "step")]
step_on_block: bool,
}

impl DecisionFormatterSettings {
Expand Down Expand Up @@ -1120,6 +1124,7 @@ impl DecisionFormatterSettings {
.with_solver_to_run(self.solver_to_run.into())
.with_search_space_size(self.show_search_size)
.with_stop_on_block(self.stop_on_block)
.with_step_on_block(self.step_on_block)
.with_compare_solvers(self.compare_solvers);
Ok(builder)
}
Expand Down
78 changes: 55 additions & 23 deletions crates/spk-solve/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,25 +92,6 @@ pub fn format_note(note: &Note) -> String {
}
}

pub fn change_is_relevant_at_verbosity(
change: &Change,
verbosity: u8,
stop_on_block: bool,
) -> bool {
use Change::*;
let relevant_level = match change {
SetPackage(_) => 1,
// More relevant when stop-on-block is enabled.
StepBack(_) if stop_on_block => 0,
StepBack(_) => 1,
RequestPackage(_) => 2,
RequestVar(_) => 2,
SetOptions(_) => 3,
SetPackageBuild(_) => 1,
};
verbosity >= relevant_level
}

/// How long to wait before showing the solver status bar.
const STATUS_BAR_DELAY: Duration = Duration::from_secs(5);

Expand Down Expand Up @@ -208,17 +189,57 @@ where
Ok(())
}

fn wait_for_user_to_hit_enter(&self) -> Result<()> {
let mut _input = String::new();

use std::io::Write;
let _ = std::io::stdout().flush();

if let Err(err) = std::io::stdin().read_line(&mut _input) {
// If there's some stdin can't be read, it is probably
// better to continue with the solve than error out.
tracing::warn!("{err}");
}
Ok(())
}

pub fn change_is_relevant_at_verbosity(&self, change: &Change) -> bool {
use Change::*;
let relevant_level = match change {
SetPackage(_) => 1,
// More relevant when stop-on-block is enabled.
StepBack(_) if self.settings.stop_on_block || self.settings.step_on_block => 0,
StepBack(_) => 1,
RequestPackage(_) => 2,
RequestVar(_) => 2,
SetOptions(_) => 3,
SetPackageBuild(_) => 1,
};
self.verbosity >= relevant_level
}

pub fn iter(&mut self) -> impl Stream<Item = Result<String>> + '_ {
stream! {
let mut stop_because_blocked = false;
let mut step_because_blocked = false;
'outer: loop {
if let Some(next) = self.output_queue.pop_front() {
yield Ok(next);
continue 'outer;
}

// Check if the solver should stop because the last
// decision was a step-back (BLOCKED) with stop-on-block set
// Check if the solver should pause because the last
// decision was a step-back (BLOCKED) with step-on-block set
if step_because_blocked {
yield(Ok(format!("{}", "Pausing at BLOCKED state. Press 'Enter' to continue.".to_string().yellow())));
if let Err(err) = self.wait_for_user_to_hit_enter() {
yield(Err(err));
}
step_because_blocked = false;
}

// Check if the solver should stop because the last decision
// was a step-back (BLOCKED) with stop-on-block set
if stop_because_blocked {
yield(Err(Error::SolverInterrupted(
format!("hit BLOCKED state with {STOP_ON_BLOCK_FLAG} enabled."),
Expand Down Expand Up @@ -330,15 +351,16 @@ where
new_level = destination.state_depth;
// Ensures the solver will stop before the next
// decision because of this (BLOCKED) change, if
// stop-on-block is enabled.
// stop-on-block or step-on-block are enabled.
stop_because_blocked = self.settings.stop_on_block;
step_because_blocked = self.settings.step_on_block;
}
_ => {
fill = ".";
}
}

if !change_is_relevant_at_verbosity(change, self.verbosity, self.settings.stop_on_block) {
if !self.change_is_relevant_at_verbosity(change) {
continue;
}

Expand Down Expand Up @@ -453,6 +475,7 @@ pub struct DecisionFormatterBuilder {
show_search_space_size: bool,
compare_solvers: bool,
stop_on_block: bool,
step_on_block: bool,
}

impl Default for DecisionFormatterBuilder {
Expand All @@ -472,6 +495,7 @@ impl Default for DecisionFormatterBuilder {
show_search_space_size: false,
compare_solvers: false,
stop_on_block: false,
step_on_block: false,
}
}
}
Expand Down Expand Up @@ -565,6 +589,11 @@ impl DecisionFormatterBuilder {
self
}

pub fn with_step_on_block(&mut self, enable: bool) -> &mut Self {
self.step_on_block = enable;
self
}

pub fn build(&self) -> DecisionFormatter {
let too_long_seconds = if self.verbosity_increase_seconds == 0
|| (self.verbosity_increase_seconds > self.timeout && self.timeout > 0)
Expand Down Expand Up @@ -606,6 +635,7 @@ impl DecisionFormatterBuilder {
show_search_space_size: self.show_search_space_size,
compare_solvers: self.compare_solvers,
stop_on_block: self.stop_on_block,
step_on_block: self.step_on_block,
},
}
}
Expand Down Expand Up @@ -666,6 +696,7 @@ pub(crate) struct DecisionFormatterSettings {
pub(crate) show_search_space_size: bool,
pub(crate) compare_solvers: bool,
pub(crate) stop_on_block: bool,
pub(crate) step_on_block: bool,
}

enum LoopOutcome {
Expand Down Expand Up @@ -756,6 +787,7 @@ impl DecisionFormatter {
show_search_space_size: false,
compare_solvers: false,
stop_on_block: false,
step_on_block: false,
},
}
}
Expand Down

0 comments on commit 506cd85

Please sign in to comment.