Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: multiple install paths with fallbacks #947

Merged
merged 8 commits into from
Apr 23, 2024
Merged

Conversation

mistydemeo
Copy link
Contributor

@mistydemeo mistydemeo commented Apr 18, 2024

This adds a new feature which allows specifying multiple paths in install-path instead of a single path. If this is set, then we use the next paths in the set as fallbacks in case the earlier options aren't available. As a result, path errors for HomeSubdir and EnvSubdir that were formerly fatal instead cause us to fall back to the next case; the only actual fatal error is if we exhaust the array of options and find nothing viable.

I've added tests for two fallback options and confirmed they work, along with a test for what happens if the first path in the array is valid and we don't perform a fallback.

I haven't fully massaged the spacing in the jinja templates to keep it from adding extra newlines in places that don't need them. I did add a comment for people reading the generated script who might be confused by what looks like a pointless if statement.

This isn't yet backwards compatible with existing Cargo.tomls for users already using install-path. I've temporarily adjusted install-path to always be an array, which will cause errors for users already using it as a string. We'll want to adjust the parsing so that a string parses to a one-length array.

@mistydemeo mistydemeo force-pushed the multiple-install-paths branch from cb266e1 to d781018 Compare April 18, 2024 23:31
@mistydemeo mistydemeo marked this pull request as draft April 19, 2024 00:14
@mistydemeo mistydemeo force-pushed the multiple-install-paths branch 3 times, most recently from 059be75 to 8131db5 Compare April 19, 2024 00:58
@Gankra Gankra marked this pull request as ready for review April 19, 2024 16:47
@Gankra Gankra force-pushed the multiple-install-paths branch from 8a935e8 to b8f496d Compare April 19, 2024 16:53
@Gankra Gankra changed the title wip: multiple install paths with fallbacks feat: multiple install paths with fallbacks Apr 19, 2024
@Gankra
Copy link
Contributor

Gankra commented Apr 19, 2024

Some pseudo-jinja-rust-shell code i think the impl should look like:

// start with nowhere to install
_install_dir = ""

// First off, if we get handed FORCE_INSTALL_DIR, just use that
if $CARGO_DIST_FORCE_INSTALL_DIR {
   // two major families of install-strategy, that the updater 
   %if strategies.contains("cargo_home") && strategies.len == 1
      _install_dir="$CARGO_DIST_FORCE_INSTALL_DIR/bin"
      _env_script_path="$CARGO_DIST_FORCE_INSTALL_DIR/env"
      _install_dir_expr="$(echo "$CARGO_DIST_FORCE_INSTALL_DIR/bin" | sed "s,$HOME,\$HOME,")"
      _env_script_path_expr="$(echo "$CARGO_DIST_FORCE_INSTALL_DIR/env" | sed "s,$HOME,\$HOME,")"
   %elseif !strategies.contains("cargo_home")
      _install_dir="$CARGO_DIST_FORCE_INSTALL_DIR"
      _env_script_path="$CARGO_DIST_FORCE_INSTALL_DIR/env"
      _install_dir_expr="$(echo "$CARGO_DIST_FORCE_INSTALL_DIR" | sed "s,$HOME,\$HOME,")"
      _env_script_path_expr="$(echo "$CARGO_DIST_FORCE_INSTALL_DIR/env" | sed "s,$HOME,\$HOME,")"
   %else
      jinjaerror "cannot combine CARGO_HOME with other strategies"
   %endif
}

// Try to find an appropriate place to install
%for strategy in strategies
  // only try other strategies if one hasn't worked
  if _install_dir.is_empty() {
    %if strategy.kind == "cargo_home"
      if $CARGO_HOME {
        _install_dir = "..."
        // ...
      } else if $HOME {
         _install_dir = "..."
        // ...
      }
    %elseif strategy.kind == "home"
      if $HOME {
        _install_dir = "..."
        // ...
      }
    %elseif strategy.kind == "env"
      if ${strategy.envvar} {
        _install_dir = "..."
        // ...
      }
    %else
      jinjaerror "unimplemented strategy"
    %endif
  }
%endfor

if _install_dir.is_empty() {
  error "oopsie whoopsie no install dir"
}

// ok install paths handled, now do the rest of setup
...

Notably:

  • FORCE by construction avoids trying to think about how things were previously installed
  • the resulting shell is "as if" a human hand-wrote it (no functionality they can't use)
  • lots of logic shared between modes

@mistydemeo
Copy link
Contributor Author

I think your suggestion makes sense, and I did write this with the consideration we might have some more ideas about #944. In the absence of that, yeah, we have to avoid mixing strategies. I wonder if it makes more sense to consider making this an error in Rust at the place we produce the installer stuff before feeding it into jinja, or even when loading the user's config, in order to make sure we get a nicer-looking error.

@Gankra
Copy link
Contributor

Gankra commented Apr 22, 2024

I wonder if it makes more sense to consider making this an error in Rust at the place we produce the installer stuff before feeding it into jinja, or even when loading the user's config, in order to make sure we get a nicer-looking error.

oh yes absolutely, i just decided to fold it into the jinja to avoid making the idea more complicated to express

@mistydemeo mistydemeo force-pushed the multiple-install-paths branch 6 times, most recently from b917a06 to 8549290 Compare April 22, 2024 22:53
Copy link
Contributor

@Gankra Gankra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The shell is looking great, just some minor nits.

Comment on lines 311 to 313
else
{% for install_path in install_paths %}
if [ -z "${_install_dir:-}" ]; then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need this else, it's implicit in the fact that CARGO_DIST_FORCE_INSTALL_DIR will set _install_dir, which nicely makes all the options look like a clean cascade :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't trying to catch it being unset from the above case. We're generating an if [] for each of the for install_path in install_paths cases, so it's letting item 2 in the array check if it was assigned in case 1, and so on.

Copy link
Contributor

@Gankra Gankra Apr 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, i'm just saying we can omit the else because every case has this if-guard, making the whole thing feel a lot more natural and removing some indentation (i applied this change)

Comment on lines 304 to 305
# For these two, if the new value contains $HOME, make
# sure to `sed` the $HOME expression back into the expr
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment should be shared between both paths

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved this up into the main comment explaining early/late

_install_dir_expr="$_install_dir"
_env_script_path_expr="$_env_script_path"
fi
elif [ -n "${HOME:-}" ]; then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can/should we restructure this so it looks like the rest of the cascade options..? (especially the final error condition)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

punted on this. it can be done but it's wonkier

Comment on lines 323 to 334
if [ -n "${HOME:-}" ]; then
if [ "$HOME/.cargo/bin" = "$_install_dir" ]; then
_install_dir_expr='$HOME/.cargo/bin'
_env_script_path_expr='$HOME/.cargo/env'
else
_install_dir_expr="$_install_dir"
_env_script_path_expr="$_env_script_path"
fi
else
_install_dir_expr="$_install_dir"
_env_script_path_expr="$_env_script_path"
fi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this all be replaced with the sed approach?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sort of. This is slightly more restricted than the sed approach, so any changes we make here would change the behaviour of the installer going forward. My goal here was to minimize side changes like this other than the big one we're changing on purpose.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah i see what you mean. I at least simplified it a bit.

err "could not find your {{ install_path.env_key }} dir to install binaries to"

if [ -z "$_install_dir_expr" ]; then
err "could not find a valid path to install to!\n\n$(usage)"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait i thought \n didn't work in shell

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh god right this is probably completely dependent on which echo is being used. I'm sure this isn't portable.

# $install_path assignment, it's because the app you're looking at
# has been configured with a single install path.
{% for install_path in install_paths %}
if (-Not $install_path) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...we should really look into if we're supposed to be wrapping these in quotes like we do in shell...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering the same thing. It's a bit inconsistent about that atm

@mistydemeo mistydemeo force-pushed the multiple-install-paths branch 4 times, most recently from a478faf to d8750f0 Compare April 23, 2024 00:24
@mistydemeo mistydemeo force-pushed the multiple-install-paths branch 2 times, most recently from 3e9eb10 to ce5f1d0 Compare April 23, 2024 00:51
@mistydemeo mistydemeo force-pushed the multiple-install-paths branch from 194a34a to 344a26b Compare April 23, 2024 01:18
@mistydemeo mistydemeo force-pushed the multiple-install-paths branch from 344a26b to 94f966a Compare April 23, 2024 01:30
@Gankra Gankra force-pushed the multiple-install-paths branch from 404a613 to 5552c8d Compare April 23, 2024 14:21
@Gankra Gankra merged commit a546b8e into main Apr 23, 2024
15 checks passed
@Gankra Gankra deleted the multiple-install-paths branch April 23, 2024 14:31
@Gankra Gankra mentioned this pull request Apr 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants