Using hypnotoad with a local-lib-contained Mojolicious install

335 views
Skip to first unread message

perlpong

unread,
Oct 18, 2014, 12:01:15 AM10/18/14
to mojol...@googlegroups.com
This is not a bug-report or a request for help, I am just sharing my experience.

I install Mojolicious inside an app-local directory using cpanm's "-L" switch:

.
|─- perl5/
|   |-- bin/
|   |   |-- hypnotoad
|   |   |-- mojo
|   |   |-- morbo
|   |-- lib/
|       |-- perl5/
|           |-- Mojo/
|           |-- Mojo.pm
|           |-- Mojolicious/
|           |-- Mojolicious.pm
|-- script/
   |-- app.pl

I run hypnotoad with Perl's "-I" flag to append my local-lib directory to the beginning of @INC:

    perl -Iperl5/lib/perl5 perl5/bin/hypnotoad ./script/myapp.pl

My app logs an error related to Mojolicious:

    Can't locate object method "every_param" via package "Mojo::Parameters"

After investigating I realise that my "global" install of Mojolicious is being loaded instead of my local one.

If I dump @INC at the beginning of the hypnotoad script, it produces this:

(
  "/home/ac/apps/MyApp/perl5/bin/../lib",
  "perl5/lib/perl5/i686-linux",
  "perl5/lib/perl5",
  "/home/ac/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1/i686-linux",
  "/home/ac/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1",
  "/home/ac/perl5/perlbrew/perls/perl-5.16.1/lib/5.16.1/i686-linux",
  "/home/ac/perl5/perlbrew/perls/perl-5.16.1/lib/5.16.1",
  ".",
)
(
  "/home/ac/apps/MyApp/perl5/bin/../lib",
  "/home/ac/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1/i686-linux",
  "/home/ac/perl5/perlbrew/perls/perl-5.16.1/lib/site_perl/5.16.1",
  "/home/ac/perl5/perlbrew/perls/perl-5.16.1/lib/5.16.1/i686-linux",
  "/home/ac/perl5/perlbrew/perls/perl-5.16.1/lib/5.16.1",
  ".",
)

It appears that the process restarts itself, the second time without my modified @INC.

Looking inside Mojo::Server::Hypnotoad, I notice this:

    $ENV{HYPNOTOAD_EXE} ||= $0;
    ...
    # Clean start (to make sure everything works)
    die "Can't exec: $!" if !$ENV{HYPNOTOAD_REV}++ && !exec $ENV{HYPNOTOAD_EXE};

So my workaround is to manually set the HYPNOTOAD_EXE environment variable:

    export HYPNOTOAD_EXE="perl -Iperl5/lib/perl5 perl5/bin/hypnotoad"
    perl -Iperl5/lib/perl5 perl5/bin/hypnotoad ./script/myapp.pl

sri

unread,
Oct 18, 2014, 12:09:47 AM10/18/14
to mojol...@googlegroups.com
So my workaround is to manually set the HYPNOTOAD_EXE environment variable:

    export HYPNOTOAD_EXE="perl -Iperl5/lib/perl5 perl5/bin/hypnotoad"
    perl -Iperl5/lib/perl5 perl5/bin/hypnotoad ./script/myapp.pl

That is very dangerous, the HYPNOTOAD_EXE environment variable is undocumented and therefore for internal use only.

--
sebastian 

Jan Henning Thorsen

unread,
Oct 18, 2014, 3:12:51 AM10/18/14
to mojol...@googlegroups.com
perl -I is not inherited through exec(). You're better off using:

  PERL5LIB=$PWD/perl5/lib/perl5 $PWD/perl5/bin/hypnotoad

This way, PERL5LIB is set for the current process and all the sub processes started with exec(). Note the $PWD part, which will make sure it's set to an absolute path.

Roland Lammel

unread,
Oct 18, 2014, 7:20:14 AM10/18/14
to mojol...@googlegroups.com
I recently startet to use a small wrapper script to setup the environment (including cpan module installation with cpanfile and cpanm) to allow our jenkins server to perform clean testing of the git master.

Everything needed apart from already installed system perl is stuffed in ./local and used with eval `perl -Mlocal::lib=local` to setup the env and exec the actuall app (in our case prove for testing or hypnotoad for production serving).

Works out very well, as also devs can now simply setup a new environment in one shot.

Does not fit in every development or deployment process, but for us it seems to work out for now.

BR

+rl

--
You received this message because you are subscribed to the Google Groups "Mojolicious" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mojolicious...@googlegroups.com.
To post to this group, send email to mojol...@googlegroups.com.
Visit this group at http://groups.google.com/group/mojolicious.
For more options, visit https://groups.google.com/d/optout.

s...@alexbyk.com

unread,
Oct 18, 2014, 9:18:28 AM10/18/14
to mojol...@googlegroups.com
Why not to use Carton?
carton exec hypnotoad script/my_app.pl

Roland Lammel

unread,
Oct 18, 2014, 9:50:44 AM10/18/14
to mojol...@googlegroups.com
Thanks for the hint, I planned looking into it for the past 2 years ;-)
We need to do some additional stuff too (like copying a basic config for testing, setup some dirs), so we need our wrapper anyway currently.

+rl

s...@alexbyk.com

unread,
Oct 18, 2014, 10:10:08 AM10/18/14
to mojol...@googlegroups.com
Actually, you don't need addition stuff like copying a basic config for testing and so on.

I can suggest:
- setup config in your_app.testing.conf files. .testing for tests, .development for dev. and .production for production
- If you use passwords in your config files, always provide passwords in different files like app.MODE.conf.private and load them directly
      $self->plugin('Config', ext => $self->mode() . '.conf.private'); Don't forget to add *.private to .gitignore
- set MOJO_MODE=testing (you can do that via BEGIN {} block in you tests, I prefer to use subclass of Test::Mojo), your tests will load .testing.conf files without modification and copying something to somewere
- setup dome dirs in the tmp directory. That's a normal practice. For example
my $tmpdir  = io()->tmpdir . "/yourapp/(and maybe some uniq part)";

Deployment will look like that
git pull
carton exec script/your_app test
carton exec hypnotoad script/your_app

You can invest 1h into trying that basics and save a lot of time in the future, and avoid writing some wrappers.

Reply all
Reply to author
Forward
0 new messages