Folder is in $INC but module loads from other location - perl

I need to test my project with new module version.
But for some reason Perl can not load it.
docker-compose run -v /data/projects/My-Module:/perl5lib project-container perl -I/perl5lib -MMy::Module -e 'print $INC{"My/Module.pm"}'
It must print
/perl5lib
But in fact it prints
/usr/local/share/perl/5.26.1/My/Module.pm
Same result with
docker-compose run -e PERL5LIB=/perl5lib -v /data/projects/My-Module:/perl5lib project-container perl -MMy::Module -e 'print $INC{"My/Module.pm"}'
Please help me to find what could be the issue.
$ perl --version
This is perl 5, version 26, subversion 1 (v5.26.1) built for x86_64-linux-gnu-thread-multi
$ docker-compose --version
docker-compose version 1.24.1, build 4667896

With this command (which should be more-or-less equivalent to what you are doing)
docker run perl:5.28 perl -I/xyz -V
Regardless /xyz exists or not within the container instance, I can visually confirm that /xyz is the first entry of #INC:
...
Compiled at Aug 15 2019 02:34:38
#INC:
/xyz
/usr/local/lib/perl5/site_perl/5.28.2/x86_64-linux-gnu
/usr/local/lib/perl5/site_perl/5.28.2
/usr/local/lib/perl5/vendor_perl/5.28.2/x86_64-linux-gnu
/usr/local/lib/perl5/vendor_perl/5.28.2
/usr/local/lib/perl5/5.28.2/x86_64-linux-gnu
/usr/local/lib/perl5/5.28.2
Given by your message that My/Module.pm got required from an alternative place, I'd guess that your /perl5lib is empty, or simply does not contain My/Module.pm -- or somehow that alternative path comes first then your /perl5lib. Not sure how that would be the case, but I'm trying to enumerate some possibilities.
Anyway, you should be able to inspect the content of /perl5lib by running
docker-compose run -v /data/projects/My-Module:/perl5lib project-container find /perl5lib
(I guess find command is available in your container, but if not, try ls -R or something similar...)
Last... in case you are using Docker on macOS -- which I cannot tell from the information you provided -- you need to verify that the /data/projects/My-Module is in the list of "File Sharing" preference. Otherwise that folder cannot be mounted.

Related

How to use the --name argument to getopt?

In the following example, I expected the error message to come from xyz, not from getopt. What am I doing wrong?
/tmp> getopt --name xyz --options "xyz:" -- -x
-x --
/tmp> getopt --name xyz --options "xyz:" -- -x -z
getopt: option requires an argument -- z
-x --
How do I make it say xyz: option requires an argument -- z; isn't that what --name is for?
UPDATE
Seems to be a bug. My getopt comes from cygwin
$ getopt --version
getopt from util-linux 2.25.2
It seems to be bug in some versions of the program.
It works for me in in Centos 7.3 and Fedora 19
[vps1 ~]$ cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)
[vps1 ~]$ getopt --name xyz --options "xyz:" -- -x -z
xyz: option requires an argument -- 'z'
-x --
[vps1 ~]$ getopt -V
getopt from util-linux 2.23.2
But it doesn't in my MinGW shell (from Git for Windows)
$ getopt --name xyz --options "xyz:" -- -x -z
getopt: option requires an argument -- z
-x --
$ getopt -V
getopt from util-linux 2.26.2
Update: It works also in 2.27.1 in Linux. And it doesn't work in (at least some version of) Cygwin. So the problem seems to be in the Windows ports (both Mingw and Cygwin, interestingly).
I'll throw a wild guess (not big probability of hitting the target):
The getopt program, since this commit tries to deal with some environnments (in particular, BSD; not Linux) that have/use the getprogname/setprogname to get/set the "current" program name (instead of relying on argv[0]).
#if defined (HAVE_SETPROGNAME) && !defined (__linux__)
setprogname(name);
Now, let's imagine that
Cygwin and MinGW/Msis both support those functions.
However, they lack the HAVE_SETPROGNAME define
Further, their getopt functions (mind you, not the program), just like the BSD version, use getprogname instead of argv[0]
In that case, the problem would be explained. However, I'm skeptical - of point 3 especially.
This is a bug (or just a non-portability issue) which is already fixed in util-linux 2.28, by commit 30fbf2f6. Before this fix it worked only on Linux, OSX and a few BSD flavors but not on WIN32 or GNU-Hurd for example.
If you can't upgrade util-linux (might be difficult to build on windows), then you could use this shell workaround:
bash -c 'exec -a "XYZ" getopt --options "xyz:" -- -x -z'
Note that still using the --name option would override this trick again once if getopt will be updated one day.
Of course you could also simply copy/link/rename the getopt program to whatever name you want.

How to send data to command line after calling .sh file?

I want to install Anaconda through EasyBuild. EasyBuild is a software to manage software installation on clusters. Anaconda can be installed with sh Anaconda.sh.
However, after running I have to accept the License agreement and give the installation location on the command line by entering <Enter>, yes <Enter>, path/where/to/install/ <Enter>.
Because this has to be installed automatically I want to do the accepting of terms and giving the install location in one line. I tried to do it like this:
sh Anaconda.sh < <(echo) >/dev/null < <(echo yes) >/dev/null \
< <(echo /apps/software/Anaconda/1.8.0-Linux-x86_64/) > test.txt
From the test.txt I can read that the first echo works as <Enter>, but I can't figure out how to accept the License agreement, as it sees it now as not sending yes:
Do you approve the license terms? [yes|no]
[no] >>> The license agreement wasn't approved, aborting installation.
How can I send the yes correctly to the script input?
Edit: Sorry, I missed the part about having to enter more then one thing. You can take a look at writing expect scripts. thegeekstuff.com/2010/10/expect-examples. You may need to install it however.
You could try piping with the following command: yes yes | sh Anaconda.sh. Read the man pages for more information man yes.
Expect is a great way to go and probably the most error proof way. If you know all the questions I think you could do this by just writing a file with the answers in the correct order, one per line and piping it in.
That install script is huge so as long as you can verify you know all the questions you could give this a try.
In my simple tests it works.
I have a test script that looks like this:
#!/bin/sh
echo -n "Do you accept "
read ANS
echo $ANS
echo -n "Install path: "
read ANS
echo $ANS
and an answers file that looks like this:
Y
/usr
Running it like so works... perhaps it will work for your monster install file as well.
cat answers | ./test.sh
Do you accept Y
Install path: /usr
If that doesn't work then the script is likely flushing and you will have to use expect or pexpect.
Good luck!
Actually, I downloaded and looked at the anaconda install script. Looks like it takes command line arguments.
/bin/bash Anaconda-2.2.0-Linux-x86_64.sh -h
usage: Anaconda-2.2.0-Linux-x86_64.sh [options]
Installs Anaconda 2.2.0
-b run install in batch mode (without manual intervention),
it is expected the license terms are agreed upon
-f no error if install prefix already exists
-h print this help message and exit
-p PREFIX install prefix, defaults to /home/cody.stevens/anaconda
Use the -b and -p options...
so use it like so:
/bin/bash Anaconda-2.2.0-Linux-x86_64.sh -b -p /usr
Also of note.. that script explicitly says not to run with '.' or 'sh' but 'bash' so they must have some dependency on a feature of bash.
--
Cody

mod_perl odd behaviour with system() or exec() call or backticks

I developped a simple script in Perl that let's me verify if USB key is mounted or not and eventually unmount it.
I am not sure if problem is related to programming or configuration, if I was wrong let me know and I will repost my question on server configuration related stack.
Basic issue is:
When I execute those scripts in terminal using Perl it works perfectly fine, althou when I do it in the browser using mod_perl it shows some pretty odd behaviour.
Sources
panelmin.pl
This program simply outputs a message that indicates if the system device /dev/sda1 is mounted in the system.
#!/usr/bin/perl
use strict;
use warnings;
print "Content-type:text/html\n\n";
print "<html><head><title>USB test</title>";
print "</head><body>";
my $mounted = `df -h | grep /dev/sda1`;
if ($mounted eq '') {
print '<h1>USB device not connected</h1>';
print $mounted;
}
else {
print '<h1>Device is connected</h1>';
}
print '</body></html>';
umount.pl
This program umounts the /dev/sda1 device from the system.
#!/usr/bin/perl
print "Content-type:text/html\n\n";
print "<html><head><title>Umount</title></head><body>";
system("sudo", "umount", "/dev/sda1");
print "</body></html>";
Test scenario
Manually mounting the device /dev/sda1, (it is declared in fstab):
$ mount -a
Making sure the device is mounted in the system:
$ mount
/dev/sda1 on /mnt/usbstick type vfat (rw,relatime,uid=1000,gid=1000,fmask=0137,dmask=0027,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro)
Executing panelmin.pl in the web browser (I will use curl for the purpose of clean output):
$ curl http://localhost/cgi-bin/admin/Q/panel/panelmin.pl
<html><head><title>USB test</title></head><body><h1>Device is connected</h1></body></html>
As we can see, the output is correct. It detected the through linux command df -h that the device /dev/sda1 is mounted in the system.
Executing umount.pl in the web browser in order to umount the device:
$ curl http://localhost/cgi-bin/admin/Q/panel/umount.pl
<html><head><title>Umount</title></head><body></body></html>
Verifying if the device is umounted using both panelmin.pl script in the web browser and linux command line.
$ curl http://localhost/cgi-bin/admin/Q/panel/panelmin.pl
<html><head><title>USB test</title></head><body><h1>USB device not connected</h1></body></html>
Seems to be correct, but let's verify it manually with df -h command:
$ df -h | grep /dev/sda1
/dev/sda1 15G 366M 15G 3% /mnt/usbstick
As we can see the device is still mounted in the system.
Let's retry the whole process but this time instead of executing scripts in the browser we will launch them manually with Perl in the terminal. First lets umount the device. This will also show that the user is in sudoers and script can umount it.
$ sudo umount /dev/sda1
$ df -h | grep /dev/sda1
Let's repeat the process.
$ mount -a (as superuser)
$ df -h | grep /dev/sda1
/dev/sda1 15G 366M 15G 3% /mnt/usbstick
And finally the test:
$ perl panelmin.pl
Content-type:text/html
<html><head><title>USB test</title></head><body><h1>Device is connected</h1></body>
$ perl umount.pl
Content-type:text/html
<html><head><title>Umount</title></head><body></body></html>
$ perl panelmin.pl
Content-type:text/html
<html><head><title>USB test</title></head><body><h1>USB device not connected</h1></body></html>
$ df -h | grep /dev/sda1
Now df -h | grep /dev/sda1 returned empty string, it has proven that umount.pl managed to umount the device from the system, but only if executed in the shell with Perl.
Attempts to solve the issue
Making sure the user who executes sudo umount /dev/sda1 in umount.pl has right to do so, I verified it by executing whoami inside the script and printing it in the output.
Trying different syntax of system(), for example separating the arguments or executing it all as one command.
I verified if my mod_perl executes scripts in taint mode, because I heard it may influence executing external processes. As a matter of fact in my httpd.conf there is no PerlTaintCheck On and if I understand it correctly, it would influence the execution with dynamic arguments (for security reasons), in case of my script it is same command each time.
I tryed to use different functions, replace System by Exec or by backticks etc.
I tryed to use Apache2::SubProcess, just like they do it here , but I must admit I'm not sure if I did it correctly, I'm new to Perl and this (and all other available on net) example is just horrible, for example $r variable is never initiated in their code, I just declarated it as Apache2::RequestRec object, it didn't work.
I tryed to change env variables like they explained here in subsection 10.2.6. Starting a Long-Running External Program
I verified the logs in Apache directory, have found errors but not related to those scripts, I didn't post them here because I didn't wanted it to bee too messy.
Interpretation
The fact it works with Perl and not with mod_perl is not that surprising, what I find the most strange is with mod_perl the script panelmin.pl seems to works fine with it's system() launch and suddenly after executing umount.pl it does not work correctly anymore. For now I am out of ideas, I find this behaviour odd and I count on you guys. I hope someone knows what should I do. Thanks.
Requested results
Capturing the output of System in umount.pl.
#!/usr/bin/perl
print "Content-type:text/html\n\n";
print "<html><head><title>Umount</title></head><body>";
my $res = `sudo umount /dev/sda1`;
print "$res</body></html>";
And the result is void:
$ curl http://localhost/cgi-bin/admin/Q/panel/umount.pl
<html><head><title>Umount</title></head><body></body></html>
It turned out the issue was not programming related, it was server configuration related.
It was Apache's fault. It worked in multithread / multiprocess environment. I'm not sure why, but it made him be unable to process system() functions. When I limited it to work in single process mode the issue was solved.
Even knowing the problem is not programming related, I think it should stay here, since when this issue occur, it may be difficult to identify the source of the problem and I suppose StackOverflow would be the first place to look for for most beginners.

How to RUN plenv/rbenv in Dockerfile?

I want to use plenv to have perl 5.16 in the docker image. apt-get only get 5.14.
plenv will install perl in $HOME/.plenv/versions/5.16.2/, and I need to append some lines into $HOME/.profile:
export PATH="$HOME/.plenv/bin:$PATH"
eval "$(plenv init -)"
Then run plenv shell 5.16.2 to swith to the new version.
But in Dockerfile, I need to write source $HOME/.profile && plenv shell 5.16.2 everyline before I run some perl commands. docker didn't exec $HOME/.profile, is it a no-login shell?
Though I could write such command before every RUN, how can I do this in CMD line?
Do docker can solve this by some setting?
You can use the ENTRYPOINT command to prepend something before each executions or you can simply move your .profile within your .bashrc.
Indeed, docker is a no-login shell, it will not run upstart, simply execute the requested process.

Cygwin commands don't work

I'm sorry that my question seems rather vague but this is the entire problem i'm facing. I tried installing an rpm package on cygwin after downloading it from the website but i always get the same error
-bash: rpm: command not found
and I have reinstalled it twice, but i always get the same problem, and it's not just that, i can't even use simple commands like ls. Even if i write ls I get no output. This is what my screen looks like.
User#User-PC ~
$ rpm -ivh avr-binutils-2.17tinyos-3.cygwin.i386.rpm
-bash: rpm: command not found
User#User-PC ~
$ locate rpm | grep bin
User#User-PC ~
$
User#User-PC ~
$ ls
User#User-PC ~
$
what do I do to fix this?
First, locate does not auto-update itself; you must run updatedb periodically to get the current list of files. For optimal speed and usability, add the --prunepaths and --prunefs switches.
Second, try echo $PATH to see the current path, and call ls with a fully-qualified pathname: /bin/ls -l
I suspect ls is set to an invalid alias or internal function (bad command parameters). Check the contents of ~/.bash_profile, ~/.bashrc, and ~/.profile .