yarnpkg / berry

📦🐈 Active development trunk for Yarn ⚒
https://yarnpkg.com
BSD 2-Clause "Simplified" License
7.44k stars 1.11k forks source link

[Feature] Portable scripts #200

Open bgotink opened 5 years ago

bgotink commented 5 years ago

Describe the user story

As a package developer I have run into issues where run-scripts depend on the system, e.g. most often because of a binary that was globally installed on one system but not another, but also because of environments.

Describe the solution you'd like

I'd like a way to tell a run-script it cannot use any system-provided executable or environment variable, preferably with a whitelist of environment variables to allow, e.g. CI to allow the script to check whether it's running on a dev machine or a CI environment.

Example API:

{
  "scripts": {},
  "scriptsMeta": {
    "onlyLocalCommands": true,
    // alternatively, "env" > "whitelist" to allow for a "blacklist" as well
    "envWhitelist": ["CI"]
  }
}

Describe the drawbacks of your solution

Not allowing system-provided executables means we don't get access to any of the GNU coreutils on Linux, BSD coreutils on BSD/macOS or any other commands available on the system. Script authors would either have to depend on packages like rimraf to provide an rm -rf alternative, or someone would have to provide a more complete tooling.

Note that the someone providing a set of utility commands doesn't have to be yarn. I could install cash-ls to get a basic ls function. We could even end up with @gnu/coreutils and @bsd/coreutils packages, providing access to commands implementing the coreutils with GNU's leniency or BSD's POSIX-compliance.

Describe alternatives you've considered

arcanis commented 5 years ago

I think you can already implement it by writing a plugin that hook into setupScriptEnvironment. Then you can modify the PATH variable to contain whatever you want (probably want to keep the first path in the set as its the one Yarn created). How does that sound?

bgotink commented 5 years ago

I would need access to the Workspace rather than the Project if the configuration is part of the package manifest. An alternative would be to place it in the .yarnrc. To be honest, if you wan to whitelist environment variables, I'm pretty sure you'll want those for the entire project rather than repeat them per workspace. The same goes for the onlyLocalCommands flag. Yarnrc makes more sense, so I'll go with that

arcanis commented 5 years ago

I'm going to assume your use case is solved, feel free to reopen if that's not the case 👍

bgotink commented 5 years ago

It has taken some time for me to be able to look further into this, with holidays and now the heat leading me to stay away from computers at home 😅

I can provide a plugin that cleans out the PATH and env quite easily (although there are three environment variables I musn't remove: PATH, NODE_OPTIONS and BERRY_BIN_FOLDER)

but this still leaves me with a broken script environment because all the wrapper script files berry generates start with #!/usr/bin/env bash which requires bash to be found on the PATH. I can think of a couple of solutions:

  1. Whitelist $(dirname $(which bash)) in the PATH as well, but that defeats the purpose of the plugin
  2. Symlink ${BERRY_BIN_FOLDER}/bash to $(which bash)
  3. Switch out the bash wrapper script with a node script

I'm liking the second option best.

My WIP code can be found at https://github.com/bgotink/berry/commit/b861f47128a4680e7dfb6dbe76b2593a238073be. I'm not sure if you want this to be part of berry as an opt-in plugin or if I should write this under a personal/work project instead?