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

Stdenv setup misc cleanups #27336

Merged
merged 6 commits into from
Jul 13, 2017

Conversation

Ericson2314
Copy link
Member

@Ericson2314 Ericson2314 commented Jul 12, 2017

Motivation for this change

@grahamc showed me shellcheck, which I am now quite fond of. In order to tightening things up so #26805 is easier to debug, I did these clean ups.

I left the # shellcheck disable=... in there in hopes we can eventually make it a test. A lot of this quoting doesn't by us much since other things block store paths with whitespace, but shellcheck can also make switching toset -u feasible, which is definitely worthy of static analysis.

This is easiest to review commit-by-commit:

  1. Use associative arrays to accumulate deps. Then instead of doing huge pattern match just check the key, and do get out deps iterator through keys.
  2. Shell check
  3. Few style + error handling things on substitue
Things done

Rebuilt Linux and Darwin stdenvs.

@@ -211,7 +211,7 @@ stdenv.mkDerivation ({
configureFlags="${concatStringsSep " " defaultConfigureFlags} $configureFlags"

# nativePkgs defined in stdenv/setup.hs
for p in $nativePkgs; do
for p in "${!nativePkgs[@]}"; do
Copy link
Member

Choose a reason for hiding this comment

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

Does this work? Isn't the ${} escaping into nix?

Copy link
Member Author

@Ericson2314 Ericson2314 Jul 12, 2017

Choose a reason for hiding this comment

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

Weird you would think, but I did build it. ah building nevermind building stdenv wouldn't catch that. Thanks!

…d of strings

This is generally cleaner: less eval, less worrying about separators,
and probably also faster. I got the idea from that python wrapper
script.
I took some liberties with the flags-echoing code to make it more
concise and correct. Also, a few warnings in findInputs and friends I
skipped because I am going to rewrite those anyways.

Thanks @grahamc for telling me about this great linter!
local input="$1"
local output="$2"
local input=$1; shift
local output=$1; shift
Copy link
Contributor

Choose a reason for hiding this comment

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

shift also takes a numeric argument, so you can do e.g., local foo=$1 bar=$2; shift 2 to achieve the same effect.

Copy link
Member Author

Choose a reason for hiding this comment

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

I short of like the "one variable, one shift" correspondence, but I'd be happy to change it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Looks a bit odd to me, but it's entirely superficial :)

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah I can avoid binding p doing this. Swayed :).

It now blows up on null byte in file (rather than silently truncating),
and invalid arguments (rather than silently skipping).
local input="$1"
local output="$2"
local input=$1
local output=$2
Copy link
Member

Choose a reason for hiding this comment

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

Why no quotes here?

Copy link
Member Author

@Ericson2314 Ericson2314 Jul 13, 2017

Choose a reason for hiding this comment

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

Bash parses it the same either way! I learned this and was quite surprised.

Copy link
Member Author

Choose a reason for hiding this comment

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

I could leave as is, but I figured given it didn't matter I should pick one and be consistent. I could normalize the other way if you like.

Copy link
Member Author

@Ericson2314 Ericson2314 Jul 13, 2017

Choose a reason for hiding this comment

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

Copying from the bash because it's really quite unbelievable for me still:

$ set -x; x='asdf asdf'; y=$x; z="$x"
+ set -x
+ x='asdf asdf'
+ y='asdf asdf'
+ z='asdf asdf'

Copy link
Contributor

Choose a reason for hiding this comment

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

This is covered under PARAMETERS in the bash manual. Word splitting & pathname expansion is not performed on assignment.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't find this an improvement, it's just forces people to learn another special case in bash syntax instead of using the obviously safe variant.

Copy link
Member

Choose a reason for hiding this comment

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

Agree with @dezgeg here. Shell quoting is such a pain and source of subtle bugs already; although it may be technically correct, why not be explicit when we can do so trivially? This particular gun might have a fancy high tech anti-foot-shot protection device in it, but I'd rather just point it away from my feet.

Copy link
Member

Choose a reason for hiding this comment

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

Uh, I hate how the bash language is so complex.

Copy link
Member Author

Choose a reason for hiding this comment

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

I basically got bash Stockholm syndrome writing this stuff. Happy to quote everything for consistency.

@@ -727,17 +742,23 @@ configurePhase() {
buildPhase() {
runHook preBuild

if [ -z "$makeFlags" ] && ! [ -n "$makefile" -o -e "Makefile" -o -e "makefile" -o -e "GNUmakefile" ]; then
if [ -z "$makeFlags" ] && ! [[ -n "$makefile" || -e "Makefile" || -e "makefile" || -e "GNUmakefile" ]]; then
Copy link
Member

Choose a reason for hiding this comment

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

Can't this be written as a single [[...]] test? Something like

if [[ -z $makeFlags && ! ( -n $makefile || ... ) ]]; then

Note that quotes are not necessary inside [[...]].

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes it can. Will do.

@edolstra
Copy link
Member

Looks good to me!

eval $var="'${!var} $pkg '"
# Stop if we've already added this one
[[ -z "${varDeref["$pkg"]}" ]] || return 0
varDeref["$pkg"]=1
Copy link
Member

Choose a reason for hiding this comment

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

This is great because it fixes the O(n^2) performance setting up the environment!

foo=$1 surprisingly doesn't need quotes in Bash. Word splits are only
syntactic in string variable (not array var!) assignments.
@Ericson2314
Copy link
Member Author

Doing another build with those changes, and then will merge.

$installFlags "${installFlagsArray[@]}"
$installFlags "${installFlagsArray[@]}")

printf 'install flags:'
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this multiple commands?

Copy link
Member Author

Choose a reason for hiding this comment

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

@dezgeg it hash to be:

  1. print the name of the flags
  2. repeat the format string (unquoted space + quoted arg) for each argument
  3. close the line

printf repeats the format string until all the args are gone, so it is essential the repeated format string contain one a single substitution.

Copy link
Member Author

Choose a reason for hiding this comment

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

I could add a helper function and comments for this :).

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah.

local content
# read returns non-0 on EOF, so we want read to fail
if IFS='' read -r -N 0 content < "$input"; then
echo "${FUNCNAME[0]}(): ERROR: File \"$input\" has null bytes, won't process" >&2
Copy link
Contributor

Choose a reason for hiding this comment

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

substitute is documented to work on binaries in the manual:

It supports performing substitutions on binary files (such as executables), though there you’ll probably want to make sure that the replacement string is as long as the replaced string.

Copy link
Member Author

Choose a reason for hiding this comment

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

@dezgeg Woah. Well the manual is definitely wrong about that. We can use mapfile and carefully printf the missing null bytes, but I think that should be a followup PR.

@dezgeg made the good point that the reasons for doing this were not at
all intuitive.
@Ericson2314 Ericson2314 merged commit ea9af6e into NixOS:staging Jul 13, 2017
@Ericson2314 Ericson2314 deleted the stdenv-setup-cleanup branch July 13, 2017 22:41
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.

9 participants