Skip to content

[FEATURE] Inherenting pre_deploy.sh environment variables #57

@Shizcow

Description

@Shizcow

Description

I've just started using dotter, and first off must say I quite like it! Because I'm new, forgive me if I'm missing something.

I arrived at a need to do this as follows: when using dotter to place in userChrome.css for Firefox, the profile directory is not always name-static. It's located in ~/.mozilla/firefox/$PROFILE_WHATEVER.default/chrome/userChrome.css.

The most straightforward solution is to allow some way for scripting the file targets. This most easily can be done with the pre_deploy.sh script, which also allows for additional user-configurable erorr checking.

Implementation Suggestion

After research into previous issues on this repo and doing some light testing, I've come up with a somewhat clean way to do this. This solution works for unix only, but I'm pretty sure it can be done in Windows too.

This functionality can be achieved as follows:

  1. Instead of directly executing pre_deploy.sh, run it through a wrapper
  2. The wrapper should call pre_deploy.sh in such a way to preserve its environment variables
    • This can be done either with source or the . cmd syntax in sh
    • This should be done through sh because dotter already uses it and it's a POSIX shell thing
  3. Print out the environment variables in such a way that Rust can interpret and forward them to itself

Below is a proof of concept. While it does not get all the edge cases, I've outlined how to avoid all those that I know may exist:

use std::process::Command;

fn main() {
    let output = Command::new("sh")
        .args(&[
            "-c",
            "
# this could be pre_deploy.sh
# the . means 'run this as a part of the current shell'
# thus the environment variables will be taken in
. $CARGO_MANIFEST_DIR/src/test.sh 2>&1 >/dev/null
# and just print the environment variables
printenv -0

# note: in a real implementation, instead of using /dev/null:
# 1) Create a pipe FD inside of rust
# 2) Merge the FD number into this string as:
#    printenv -0 >&FDNO
# 3) Read back the pipe via rust
# This would preserve pre_deploy.sh output
",
        ])
        .output()
        .expect("failed to execute process");

    let env_vars = output
        .stdout
        .into_iter()
        .fold(vec![vec![]], |mut acc, c| {
            // Because we used printenv -0, everything is separated by null characters
            // Just need to separate on those
            if c == 0 {
                acc.push(vec![]);
            } else {
                acc.last_mut().unwrap().push(c);
            }
            acc
        })
        .into_iter()
        .map(|v| {
            // Now to separate the names from the values
            let envp = std::str::from_utf8(&v).unwrap();
            // posix compliance states that the seperator between env names and env values is the '=' character
            let i: Vec<_> = envp.splitn(2, "=").collect();
            (
                i[0].to_string(),
                i.get(1).map(|s| s.to_string()).unwrap_or(String::new()),
            )
        })
        .collect::<Vec<_>>();

    // As an example, printing out TESTENV
    // It's feasible to just use std::env::set_var over an iterator
    println!(
        "{:?}",
        env_vars
            .into_iter()
            .find(|s| s.0.starts_with("TESTENV"))
            .unwrap()
    );
}

Offer to Contribute

I'd be happy to flesh out the above solution to capture all the edge cases, and contribute it as a full solution to dotter. @SuperCuber you're in charge here -- if you think this feature is reasonable I'll gladly put the effort in. I don't want to waste time if not.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions