How to activate a virtualenv using a makefile? - makefile

At the top of my makefile I have this line:
SHELL := /bin/sh
which is needed for most of the commands. However, I would like to also have a make command to activate my virtual env, which is on a different path.
Here is the code that I wrote for it:
activate:
source ~/.envs/$(APP)/bin/activate; \
The problem with this is, that this just prints out what is written here, and it doesn't get executed. I read that it might have something todo with only bash knowing about source, but I can't figure out how to temporarily switch modes within the activate command.
How would I have to write this method, so that it activates my virtualenv?

It does get executed.
Virtualenv works by modifying your current process's environment (that's why you have to "source" it). However, one process cannot modify the environment of the other process. So, to run your recipe make invokes a shell and passes it your virtualenv command, it works, then the shell exits, and your virtualenv is gone.
In short, there's no easy way to do this in a makefile. The simplest thing to do is create a script that first sources the virtualenv then runs make, and run that instead of running make.

Create a file called "make-venv" like this:
#!/bin/bash
source ./.venv/bin/activate
$2
Then add this to the first line of your Makefile
SHELL=./make-venv
Now, make-venv activates virtualenv before every command runs. Probably inefficient, but functional.

You can do it by using set, which allows you to set or unset values of shell options and positional parameters:
set -a && . venv/bin/activate && set +a

Related

LLDB with Python problem: set PATH exclusively for one executable?

Is there a way of set the PATH variable exclusively for one executable in bash script?
I want to do so because somehow macOS's LLDB requires system-intalled Python, not my Anaconda-managed Python, therefore I need to ensure /usr/bin is at the beginning of PATH. But I prefer Anaconda-managed Python for everyday use, so I don't want to set PATH permanently just to accommodate LLDB.
Temporarily manually writing PATH before and after using LLDB is cumbersome, so I'm thinking about some kind of wrapper script or alias that automates this routine.
P.S. LLDB has the same problem with Homebrew-managed Python.
Environment variables are, by definition, per-process. Each process has a copy of the environment which it can modify for its own reasons.
To override the PATH just for a single invocation, all sh-compatible shells allow you to say
PATH=newvalue executable with arguments
which sets PATH to newvalue for the duration of the execution of executable with arguments, then reverts the value back to its previous state (the current value, or unset if it was unset).
If you want to override something in the environment every time you execute something, you need a wrapper. Assuming you have /usr/local/bin before /usr/bin in your PATH, you could install this in /usr/local/bin/something to override /usr/bin/something with a wrapper:
#!/bin/sh
PATH=newvalue
exec /usr/bin/something "$#"
Remember chmod a+x and of course you need to be root to have write access to this directory in the first place.
For your private needs, a shell function in your .profile or similar is sufficient.
something () {
PATH=newvalue command something "$#"
}

QtCreator working directory for a custom project?

I'm trying to run a Makefile for building a kernel module in QtCreator. I can successfully invoke the make file from the command line.
My assumption was that this shouldn't be a problem to set also in QtCreator by defining the build step as a custom command make.
It seems however that QtCreator is introducing some other working paths instead.
As the showcase above points, both the working directory and the script absolute path are set to /home/user/module which is the path in which the correct Makefile resides.
However, QtCreator seems to be searching for the Makefile at /home/user/Qt/Tools/QtCreator/bin/Makefile: No such file or directory.
Am I missing a setting somewhere or is this a bug?
You are using the PWD environment variable in your makefiles. This environment variable is updated only by a shell though, and custom process steps are not executed in a shell by default, but started directly as a child process. This means that PWD will stay as it is shown in the "Run Environment" section of the run configuration instead of being changed to the working directory of the step.
If your custom step depends on features of the shell, you should run it in a shell, i.e. set the "Command" to /bin/sh (or /bin/bash or whatever you prefer), and the "Arguments" to -c make (or whatever you need to pass to your preferred shell to execute a command).

How to implicitly run a shell script sourced?

I have made a shell script to run as terminal command, but the cd commands inside it is not effective and hence I want to run it with source so that the cd commands take effect.
script name : "project.sh"
I added this file to /usr/local/bin, made it executable by chmod +x project.sh and it runs fine, but the cd command is not working.
I know it runs in a child process and hence at the end terminal returns back to the starting directory, rendering no effect of cd commands inside project.sh.
The solutions presented at Sol:1 do not work for me, because they asks me to run source <file>, which is not possible if I want to use it as Bash command.
You use the source command:
source /usr/local/bin/project.sh
There's no way to make this happen automatically by typing the script name, that always runs the script in a subprocess. If you don't want to have to type this all out, you could create an alias in your .bashrc to simplify it:
alias project='source /usr/local/bin/project.sh'
Then typing project will be translated to that full command.
Of course, source <file> is a Bash command - it uses the source builtin to run script <file> in the context of the current shell rather than in a child process, thus allowing commands in <file> to change the current shell's environment, such as in terms of the working directory (using cd).
Using source, or its alias ., is (ultimately) the only way to achieve that.
If your intent is not to have to invoke <script> explicitly with source, you have two options, both of which are best defined in your Bash profile, ~/.bash_profile (since you're on OS X; on Linux, use ~/.bashrc[1]):
I'll assume that your script is /path/to/foo, and that you want to invoke it sourced as just foo:
Option 1: Define an alias: alias foo='source "/path/to/foo"'
Option 2: Define a function: foo() { source "/path/to/foo"; }
Both aliases and functions execute in the current shell, allowing you to effectively hide the source call behind a single command; aliases are generally a little easier to define, but functions offer more flexibility.
By virtue of the alias / function being defined in your Bash profile, which itself is implicitly sourced, the commands in /path/to/foo will affect your interactive shells' environment.
Note: Either definition of foo will only be available in interactive shells (those that (automatically) source ~/.bash_profile).
Additional steps would be needed to make foo work inside non-sourced scripts as well, but at that point you should ask yourself whether you're obscuring things by not making the fact that /path/to/foo is getting sourced explicit.
If you're writing a script that must be sourced for distribution to others:
Install the sourcing command in the user's shell profile / initialization file (as described above) on installation of your script.
If there is no installation process (and also to enable on-demand installation in general), implement a command-line option for your script such as i (--install) that performs this installation on demand.
Preferably, also implement an uninstallation option.
Either way, build logic into the script so that it refuses to run when run without sourcing, and have the error message contain instructions on how to install sourcing.
See this answer for how to detect sourcing.
A real-world implementation of the above - although more elaborate due to being multi-shell - is my typex utility; source code here.
[1] On OS X, Bash instances started by Terminal.app are login shells, which means that the only (user-specific) file that is automatically sourced on startup is ~/.bash_profile.
By contrast, on most Linux systems Bash instances are non-login shells, where only ~/.bashrc is automatically sourced.
While it is common practice to source ~/.bashrc from one's ~/.bash_profile, this has to be configured manually and therefore cannot be relied upon blindly.

Activating a VirtualEnv using a shell script doesn't seem to work

I tried activating a VirtualEnv through a shell script like the one below but it doesn't seem to work,
#!/bin/sh
source ~/.virtualenvs/pinax-env/bin/activate
I get the following error
$ sh virtualenv_activate.sh
virtualenv_activate.sh: 2: source: not found
but if I enter the same command on terminal it seems to work
$ source ~/.virtualenvs/pinax-env/bin/activate
(pinax-env)gautam#Aspirebuntu:$
So I changed the shell script to
#!/bin/bash
source ~/.virtualenvs/pinax-env/bin/activate
as suggested and used
$ bash virtualenv_activate.sh
gautam#Aspirebuntu:$
to run the script .
That doesn't throw an error but neither does that activate the virtual env
So any suggestion on how to solve this problem ?
PS : I am using Ubuntu 11.04
TLDR
Must run the .sh script with source instead of the script solely
source your-script.sh
and not
your-script.sh
Details
sh is not the same as bash (although some systems simply link sh to bash, so running sh actually runs bash). You can think of sh as a watered down version of bash. One thing that bash has that sh does not is the "source" command. This is why you're getting that error... source runs fine in your bash shell. But when you start your script using sh, you run the script in an shell in a subprocess. Since that script is running in sh, "source" is not found.
The solution is to run the script in bash instead. Change the first line to...
#!/bin/bash
Then run with...
./virtualenv_activate.sh
...or...
/bin/bash virtualenv_activate.sh
Edit:
If you want the activation of the virtualenv to change the shell that you call the script from, you need to use the "source" or "dot operator". This ensures that the script is run in the current shell (and therefore changes the current environment)...
source virtualenv_activate.sh
...or...
. virtualenv_activate.sh
As a side note, this is why virtualenv always says you need to use "source" to run it's activate script.
source is an builtin shell command in bash, and is not available in sh. If i remember correctly then virtual env does a lot of path and environment variables manipulation. Even running it as bash virtualenv_blah.sh wont work since this will simply create the environment inside the sub-shell.
Try . virtualenv_activate.sh or source virtualenv_activate.sh this basically gets the script to run in your current environment and all the environment variables modified by virtualenv's activate will be available.
HTH.
Edit: Here is a link that might help - http://ss64.com/bash/period.html
On Mac OS X your proposals seems not working.
I have done it this way. I'am not very happy with solution, but share it anyway here and hope, that maybe somebody will suggest the better one:
In activate.sh I have
echo 'source /Users/andi/.virtualenvs/data_science/bin/activate'
I give execution permissions by: chmod +x activate.sh
And I execute this way:
`./activate.sh`
Notice that there are paranthesis in form of ASCII code 96 = ` ( Grave accent )
For me best way work as below.
Create start-my-py-software.sh and pest below code
#!/bin/bash
source "/home/snippetbucket.com/source/AIML-Server-CloudPlatform/bin/activate"
python --version
python /home/snippetbucket.com/source/AIML-Server-CloudPlatform/main.py
Give file permission to run like below.
chmod +x start-my-py-software.sh
Now run like below
.start-my-py-software.sh
and that's it, start my python based server or any other code.
ubuntu #18.0
In my case, Ubuntu 16.04, the methods above didn't worked well or it needs much works.
I just made a link of 'activate' script file and copy it to home folder(or $PATH accessible folder) and renamed it simple one like 'actai'.
Then in a terminal, just call 'source actai'. It worked!

Getting a 'source: not found' error when using source in a bash script

I'm trying to write (what I thought would be) a simple bash script that will:
run virtualenv to create a new environment at $1
activate the virtual environment
do some more stuff (install django, add django-admin.py to the virtualenv's path, etc.)
Step 1 works quite well, but I can't seem to activate the virtualenv. For those not familiar with virtualenv, it creates an activate file that activates the virtual environment. From the CLI, you run it using source
source $env_name/bin/activate
Where $env_name, obviously, is the name of the dir that the virtual env is installed in.
In my script, after creating the virtual environment, I store the path to the activate script like this:
activate="`pwd`/$ENV_NAME/bin/activate"
But when I call source "$activate", I get this:
/home/clawlor/bin/scripts/djangoenv: 20: source: not found
I know that $activate contains the correct path to the activate script, in fact I even test that a file is there before I call source. But source itself can't seem to find it. I've also tried running all of the steps manually in the CLI, where everything works fine.
In my research I found this script, which is similar to what I want but is also doing a lot of other things that I don't need, like storing all of the virtual environments in a ~/.virtualenv directory (or whatever is in $WORKON_HOME). But it seems to me that he is creating the path to activate, and calling source "$activate" in basically the same way I am.
Here is the script in its entirety:
#!/bin/sh
PYTHON_PATH=~/bin/python-2.6.1/bin/python
if [ $# = 1 ]
then
ENV_NAME="$1"
virtualenv -p $PYTHON_PATH --no-site-packages $ENV_NAME
activate="`pwd`/$ENV_NAME/bin/activate"
if [ ! -f "$activate" ]
then
echo "ERROR: activate not found at $activate"
return 1
fi
source "$activate"
else
echo 'Usage: djangoenv ENV_NAME'
fi
DISCLAIMER: My bash script-fu is pretty weak. I'm fairly comfortable at the CLI, but there may well be some extremely stupid reason this isn't working.
If you're writing a bash script, call it by name:
#!/bin/bash
/bin/sh is not guaranteed to be bash. This caused a ton of broken scripts in Ubuntu some years ago (IIRC).
The source builtin works just fine in bash; but you might as well just use dot like Norman suggested.
In the POSIX standard, which /bin/sh is supposed to respect, the command is . (a single dot), not source. The source command is a csh-ism that has been pulled into bash.
Try
. $env_name/bin/activate
Or if you must have non-POSIX bash-isms in your code, use #!/bin/bash.
In Ubuntu if you execute the script with sh scriptname.sh you get this problem.
Try executing the script with ./scriptname.sh instead.
best to add the full path of the file you intend to source.
eg
source ./.env instead of source .env
or source /var/www/html/site1/.env

Resources