-
Notifications
You must be signed in to change notification settings - Fork 25
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
Clean up the addition of extra directories and/or files #125
base: main
Are you sure you want to change the base?
Conversation
The rsync'ing of ~/git/extra-scripts was hacked in before run_qemu was becoming a wider distributed tool. As such it is undocumented and could potentially cause odd or unexpected behavior. The addition of the user-extras provides the same functionality with more user control. Including being explicit for the users benefit. Remove extra-scripts rsync'ing. Signed-off-by: Ira Weiny <ira.weiny@intel.com>
Depending on the use case run_qemu may need additional user space software. ndctl was specifically included and built within the root image due to the initial run_qemu use case to test pmem/dax/cxl. One option would be to hard code the addition of each user space source tree similar to ndctl. This is not desirable for a few reasons. 1) Additional source trees will start to bloat the root image. 2) ndctl was added with very specific directory locations. Some users have worked around this with symlinks but it is inflexible. 3) making source trees optional bloats the parameter space for run_qemu 4) building each user package is very specific to each package A better alternative is to allow the user to specify additional source trees; in different locations. This allows different kernel/user space source combinations in whatever combination the user requires at a specific time. Add the extra-dirs option. The extra-dirs option specifies a file containing a list of paths to user source trees. Each of these source trees is installed in the /root home directory of the guest image. Building of source trees is left to the user. Signed-off-by: Ira Weiny <ira.weiny@intel.com>
fail "$extra_dirs not found" | ||
fi | ||
echo "Installing extra directories and files from: $extra_dirs" | ||
for d in `cat "$extra_dirs"`; do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://www.shellcheck.net/wiki/SC2006
shellcheck -x run_qemu.sh
Don't forget the -x
otherwise there is a ton of false positives.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I always forget about shellcheck... I'll try it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coding shell scripts without running shellcheck is now a crime :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW there are a few other warnings we should clean up if we are going to make that a requirement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely! But shellcheck can catch codestyle issues and sometimes bugs even long before it is requirement :-) This only requires keep the number of warnings to a reasonable level not to drown the new ones.
{ | ||
local p=$1 | ||
|
||
p=$(eval echo $p) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this line do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This really sent me down a rabit hole which I could not resolve any other way.
If you don't do the eval on the $arg* variable any shell expansion will not happen. So without that eval this:
--extra-dirs=~/foo
Will not resolve to your home dir. I tried for a while to get it to work. For some reason this only happens with the argbash variables and not with other variables defined in the script. Running eval made the shell expansion work as expected. So I went with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I missed that shell expansion was an intended feature. It's really not a small thing that should be found by chance in line 155 and nowhere else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm I don't love the eval.. (also is the echo redundant anyway?)
Does something like this work?
paths=($_arg_extra_dirs)
for paths in ${paths[@]}; do
<stuff>
done
@@ -144,6 +144,21 @@ distro_vars="${script_dir}/${_distro}_vars.sh" | |||
|
|||
pushd "$_arg_working_dir" > /dev/null || fail "couldn't cd to $_arg_working_dir" | |||
|
|||
# save the working directory | |||
working_dir=$(pwd) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why save it again? It's already in "$_arg_working_dir"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pwd guarentees we have that directory's full path after doing the push where ever _arg_working_dir was.
FWIW AFAIK no one uses _arg_working_dir. So it is probably almost untested. But this seemed safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes of course. Then please:
working_dir=$(pwd) | |
abs_working_dir=$(pwd) |
Please also drop or change the comment, it threw me off.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok sure!
@@ -34,6 +34,7 @@ exit 11 #)Created by argbash-init v2.9.0 | |||
# ARG_OPTIONAL_BOOLEAN([debug], [v], [Debug script problems (enables set -x)], ) | |||
# ARG_OPTIONAL_BOOLEAN([ndctl-build], , [Enable ndctl build in root image], [on]) | |||
# ARG_OPTIONAL_BOOLEAN([kern-selftests], , [Enable kernel selftest build in root image (Warning: This option can take a long time and requires many support packages on the host; including some 32 bit)], [off]) | |||
# ARG_OPTIONAL_SINGLE([extra-dirs], , [Specify a file with a list of directories (or files) to be copied to the /root directory within the image.], []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to say that:
- Relative directories inside that file are relative to --working-dir (which defaults to
.
) - symbolic links are resolved (NOT recursively like rsync -L does, but that's impossible to summarize clearly and fairly intuitive so don't say "not recursively")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was trying to keep the help small. But yea it is probably worth noting that any relative paths are to the working directory. I'll update it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also: shell expansion that I mostly miss in the first review. It's really not a small thing.
if [[ $_arg_ndctl_build == "on" ]]; then | ||
if [ -n "$ndctl" ]; then | ||
rsync "${rsync_opts[@]}" "$ndctl/" mkosi.extra/root/ndctl | ||
prepare_ndctl_build # create mkosi.postinst which compiles | ||
fi | ||
fi | ||
|
||
if [[ "$_arg_extra_dirs" ]]; then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if [[ "$_arg_extra_dirs" ]]; then | |
if [[ -n "$_arg_extra_dirs" ]]; then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No we are not checking for the file here. See comment above about the lack of shell expansion for _arg_extra_dirs. This check is simply for the value being set. If it is set we must canonicalize it before we can check for the file. Probably worth a comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-n
is not checking for the file either. It's a string operator. It's more explicit, clearer and generally safer because variables can start with special characters (like -
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought the quotes would save us from special characters... :-/ ok I'll add it. Sorry was thinking -f.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought the quotes would save us from special characters... :-/
They may or may not depending on which test
instruction you use etc. It's complicated. I just keep it simple and always use -n
.
Same with quotes: "When in doubt, double-quote every expansion in your shell commands."
https://mywiki.wooledge.org/Quotes#I.27m_Too_Lazy_to_Read.2C_Just_Tell_Me_What_to_Do
if [[ $_arg_ndctl_build == "on" ]]; then | ||
if [ -n "$ndctl" ]; then | ||
rsync "${rsync_opts[@]}" "$ndctl/" mkosi.extra/root/ndctl | ||
prepare_ndctl_build # create mkosi.postinst which compiles | ||
fi | ||
fi | ||
|
||
if [[ "$_arg_extra_dirs" ]]; then | ||
extra_dirs=$(make_canonical_path $_arg_extra_dirs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think make_canonical_path
should not be used here, otherwise it's incompatible with shell completion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the contrary it is required for shell expansion. See comment about the if check above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shell expansion is a pretty big thing, a much bigger "feature" IMHO than "canonical_path". The function name should reflect that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok one could make the argument you are making. But the function returnes the fully qualified canonical path. That is it's purpose. I submit that passing "~/foo" should resolve to "/home//foo" and that is what the user expects. The fact that eval is used to do that is irrelavant to what the user expects.
Let me ask this another way. How else might "~" be expected to be interpreted if passed to this function?
BTW this also works through eval:
$HOME/foo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whatever happens what I don't want is to have to repeat this logic over and over for each path presented.
We could insist that all paths be absolute in the config file... Maybe that would be ok... dunno?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually like that idea. absolute paths only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me ask this another way. How else might "~" be expected to be interpreted if passed to this function?
This is really not the question. The question is: "who knows what ELSE happens when using eval
and shell expansion?" And the answer is: barely anyone!
BTW this also works through
eval
:
My point exactly! And many, many other things: https://www.gnu.org/software/bash/manual/html_node/Shell-Expansions.html
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
We could insist that all paths be absolute in the config file..
If you mean: dropping shell expansion and eval
then this would for sure simplify things tremendously. There is a reason why people say "eval is evil" :-)
But... dropping relative paths sounds like throwing the baby with the eval
bathwater. A very easy way to deal with relative paths is to temporarily change directory back to whatever base you decide. Something like:
for src_line in...
( cd $working_dir
rsync -a "$src_line" ...
)
done
If a relative "$src_line" is not found, rsync will just fail with a useful error message.
fail "$extra_dirs not found" | ||
fi | ||
echo "Installing extra directories and files from: $extra_dirs" | ||
for d in `cat "$extra_dirs"`; do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for d in `cat "$extra_dirs"`; do | |
cat "$extra_dirs" | while read d; do |
read
is guaranteed to read line by line whereas for ... in ...
splits on any whitespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yea probably better. cat just worked initially... :-D
if [[ -e $d ]]; then | ||
rsync -a "$d" mkosi.extra/root/ | ||
else | ||
fail "$d not found" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fail "$d not found" | |
fail "extra-dir directory %s not found" "$d" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I missed that you are trying to use printf style here. Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More flexible, safer, more consistent. But no big deal :-D
BTW, this looks useful and a very welcome cleanup but... I will probably not use it :-) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I missed that shell expansion was an intended feature. Is this only for expanding ~
because rsync
does not support it? I thought it did...
EDIT: Shell expansion will not just expand ~
, it will also expand *
, maybe others and it will be whitespace incompatible.
@@ -144,6 +144,21 @@ distro_vars="${script_dir}/${_distro}_vars.sh" | |||
|
|||
pushd "$_arg_working_dir" > /dev/null || fail "couldn't cd to $_arg_working_dir" | |||
|
|||
# save the working directory | |||
working_dir=$(pwd) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes of course. Then please:
working_dir=$(pwd) | |
abs_working_dir=$(pwd) |
Please also drop or change the comment, it threw me off.
if [[ $_arg_ndctl_build == "on" ]]; then | ||
if [ -n "$ndctl" ]; then | ||
rsync "${rsync_opts[@]}" "$ndctl/" mkosi.extra/root/ndctl | ||
prepare_ndctl_build # create mkosi.postinst which compiles | ||
fi | ||
fi | ||
|
||
if [[ "$_arg_extra_dirs" ]]; then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-n
is not checking for the file either. It's a string operator. It's more explicit, clearer and generally safer because variables can start with special characters (like -
)
if [[ $_arg_ndctl_build == "on" ]]; then | ||
if [ -n "$ndctl" ]; then | ||
rsync "${rsync_opts[@]}" "$ndctl/" mkosi.extra/root/ndctl | ||
prepare_ndctl_build # create mkosi.postinst which compiles | ||
fi | ||
fi | ||
|
||
if [[ "$_arg_extra_dirs" ]]; then | ||
extra_dirs=$(make_canonical_path $_arg_extra_dirs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shell expansion is a pretty big thing, a much bigger "feature" IMHO than "canonical_path". The function name should reflect that.
@@ -34,6 +34,7 @@ exit 11 #)Created by argbash-init v2.9.0 | |||
# ARG_OPTIONAL_BOOLEAN([debug], [v], [Debug script problems (enables set -x)], ) | |||
# ARG_OPTIONAL_BOOLEAN([ndctl-build], , [Enable ndctl build in root image], [on]) | |||
# ARG_OPTIONAL_BOOLEAN([kern-selftests], , [Enable kernel selftest build in root image (Warning: This option can take a long time and requires many support packages on the host; including some 32 bit)], [off]) | |||
# ARG_OPTIONAL_SINGLE([extra-dirs], , [Specify a file with a list of directories (or files) to be copied to the /root directory within the image.], []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also: shell expansion that I mostly miss in the first review. It's really not a small thing.
{ | ||
local p=$1 | ||
|
||
p=$(eval echo $p) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I missed that shell expansion was an intended feature. It's really not a small thing that should be found by chance in line 155 and nowhere else.
fail "$extra_dirs not found" | ||
fi | ||
echo "Installing extra directories and files from: $extra_dirs" | ||
for d in `cat "$extra_dirs"`; do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coding shell scripts without running shellcheck is now a crime :-)
if [[ -e $d ]]; then | ||
rsync -a "$d" mkosi.extra/root/ | ||
else | ||
fail "$d not found" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More flexible, safer, more consistent. But no big deal :-D
expanding Not sure why you say whitespace is incompatible. It seems to work for me. 14:45:10 > ls ./qbuild/mkosi.extra/root/white\ space/ |
Ok leaning toward this simplifed version which requires absolute paths in the config file. '*' is not supported. Ok I don't get how to put preformatted text in here... ok got it. 15:01:25 > git di diff --git a/run_qemu.sh b/run_qemu.sh index 1d39f9a0a02b..3e9ba4062ff2 100755 --- a/run_qemu.sh +++ b/run_qemu.sh @@ -144,22 +144,6 @@ distro_vars="${script_dir}/${_distro}_vars.sh" pushd "$_arg_working_dir" > /dev/null || fail "couldn't cd to $_arg_working_dir" -# save the working directory -working_dir=$(pwd) - -# make a path canonical to the working dir -make_canonical_path() -{ - local p=$1 - - # ensure bash expansion on $p - p=$(eval echo "$p") - pushd "$working_dir" > /dev/null - p=$(realpath "$p") - popd > /dev/null - echo "$p" -} - set_valid_mkosi_ver() { "$mkosi_bin" --version @@ -1173,14 +1157,14 @@ make_rootfs() fi # Check if extra-dirs is specified prior to making it canonical - if [[ "$_arg_extra_dirs" ]]; then - extra_dirs=$(make_canonical_path "$_arg_extra_dirs") + if [[ -n "$_arg_extra_dirs" ]]; then + extra_dirs=$(eval echo "$_arg_extra_dirs") if [[ ! -f $extra_dirs ]]; then fail "$extra_dirs not found" fi echo "Installing extra directories and files from: $extra_dirs" while read d; do - d=$(make_canonical_path "$d") + d=$(eval echo "$d") echo " $d" if [[ -e $d ]]; then rsync -a "$d" mkosi.extra/root/ |
My point exactly: expanding
I miss how relative paths are related to shell expansion, let me take a closer look. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why you say whitespace is incompatible. It seems to work for me.
It works in simple cases because echo
accepts a variable number of arguments. But you can find plenty of counter-examples, here's the first one I can think of:
a="multiple spaces"
echo $a
multiple spaces
echo "$a"
multiple spaces
https://mywiki.wooledge.org/Quotes#I.27m_Too_Lazy_to_Read.2C_Just_Tell_Me_What_to_Do
Also: in general prefer printf
over echo
, it's more predictable
https://www.shellcheck.net/wiki/SC2028
if [[ $_arg_ndctl_build == "on" ]]; then | ||
if [ -n "$ndctl" ]; then | ||
rsync "${rsync_opts[@]}" "$ndctl/" mkosi.extra/root/ndctl | ||
prepare_ndctl_build # create mkosi.postinst which compiles | ||
fi | ||
fi | ||
|
||
if [[ "$_arg_extra_dirs" ]]; then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought the quotes would save us from special characters... :-/
They may or may not depending on which test
instruction you use etc. It's complicated. I just keep it simple and always use -n
.
Same with quotes: "When in doubt, double-quote every expansion in your shell commands."
https://mywiki.wooledge.org/Quotes#I.27m_Too_Lazy_to_Read.2C_Just_Tell_Me_What_to_Do
if [[ $_arg_ndctl_build == "on" ]]; then | ||
if [ -n "$ndctl" ]; then | ||
rsync "${rsync_opts[@]}" "$ndctl/" mkosi.extra/root/ndctl | ||
prepare_ndctl_build # create mkosi.postinst which compiles | ||
fi | ||
fi | ||
|
||
if [[ "$_arg_extra_dirs" ]]; then | ||
extra_dirs=$(make_canonical_path $_arg_extra_dirs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me ask this another way. How else might "~" be expected to be interpreted if passed to this function?
This is really not the question. The question is: "who knows what ELSE happens when using eval
and shell expansion?" And the answer is: barely anyone!
BTW this also works through
eval
:
My point exactly! And many, many other things: https://www.gnu.org/software/bash/manual/html_node/Shell-Expansions.html
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
We could insist that all paths be absolute in the config file..
If you mean: dropping shell expansion and eval
then this would for sure simplify things tremendously. There is a reason why people say "eval is evil" :-)
But... dropping relative paths sounds like throwing the baby with the eval
bathwater. A very easy way to deal with relative paths is to temporarily change directory back to whatever base you decide. Something like:
for src_line in...
( cd $working_dir
rsync -a "$src_line" ...
)
done
If a relative "$src_line" is not found, rsync will just fail with a useful error message.
fail "$extra_dirs not found" | ||
fi | ||
echo "Installing extra directories and files from: $extra_dirs" | ||
for d in `cat "$extra_dirs"`; do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely! But shellcheck can catch codestyle issues and sometimes bugs even long before it is requirement :-) This only requires keep the number of warnings to a reasonable level not to drown the new ones.
After a quick "brainstorm" with @stellarhopper I think we have a simple and effective idea: add TWO new command line options offering two different user interfaces to the same feature:
All these directories and files get combined in a single list and fed to a single rsync loop.
@weiny2 , thoughts? |
The ability to add random files and directories to the root image had previously been hacked in via a secret 'special' directory location. This functionality is nice but lacking for a couple of reasons.
Remove the existing hidden feature and add --extra-dirs as a parameter which can specify a list of directories (or files) to be added to /root within the image.
This functionality was discussed in #124
This does not remove or clean up the rsync's but should make one of it's uses much more clear.
To ensure explicit usage for the user no default is provided. But directories will not be removed without a -r wipe.