I am building an Electron app (running an Angular application) which acts as the User Interface for a python program underneath.
The python program uses anaconda for package management (I am using miniconda for development).
When the app boots up, it checks whether the required conda environment exists, and if not, creates it.
The following code is part of a Service which is responsible for managing the python program.
public doEnvironmentSetup() {
let stdOutSub = new Subject<string>();
let stdErrSub = new Subject<string>();
let completeSubject = new Subject<string>();
this.runningSetup = true;
const TEMP_ENV_FILE = join(tmpdir(), "env.yml");
return Promise.resolve()
.then(() => {
// Copy packaged environment.yml to TEMP_ENV_FILE
})
.then(() => this.electron.getApplicationStoragePath())
.then((stor) => {
setTimeout(() => {
let runProcess = this.electron.childProcess.spawn("conda", ["env", "create", "--file", TEMP_ENV_FILE, "--name", CONDA_ENV_NAME], {
cwd: stor
});
const stdOutReaderInterface = createInterface(runProcess.stdout);
const stdErrReaderInterface = createInterface(runProcess.stderr);
stdOutReaderInterface.on('line', (line) => {
stdOutSub.next(line);
});
stdErrReaderInterface.on('line', (line) => {
stdErrSub.next(line);
});
runProcess.on('close', (code: number) => {
this.electron.fs.unlinkSync(TEMP_ENV_FILE);
this.runningSetup = false;
completeSubject.next("");
});
}, 2000);
return {
stdOut: stdOutSub,
stdErr: stdErrSub,
onComplete: completeSubject
};
});
}
Now, when I need to run the actual python code, the piece of code which runs is (not giving the whole thing, since it is too long for our purpose here) :
execCmd.push(
`conda init ${this.electron.os.platform() === "win32" ? "powershell" : "bash"}`,
`conda activate ${CONDA_ENV_NAME}`,
// long python spawn command
`conda deactivate`,
)
setTimeout(() => {
logLineSubject.next({ out: "--- Setting up Execution Environment ---", err: "" });
logLineSubject.next({ out: `Running in ${dir}`, err: "" });
const cmd = execCmd.join(" && ");
let runProcess = this.electron.childProcess.spawn(cmd, {
detached: false,
windowsHide: true,
cwd: cwd,
shell: this.getShell()
});
const stdOutInterface = createInterface(runProcess.stdout);
const stdErrInterface = createInterface(runProcess.stderr);
stdOutInterface.on('line', (line) => {
// get this line back to the component
});
stdErrInterface.on('line', (line) => {
// get this line back to the component
});
runProcess.on("error", (err) => {
// get this back to the component
});
runProcess.on('close', (code: number) => {
// get this line back to the component
});
}, 1000);
where getShell is defined as:
private getShell() {
return process.env[this.electron.os.platform() === "win32" ? "COMSPEC" : "SHELL"];
}
However, whenever I try to run this, it comes back with:
CommandNotFoundError: Your shell has not been properly configured to use 'conda activate'.
To initialize your shell, run
$ conda init <SHELL_NAME>
blah blah blah ...
When I try with source activate ${CONDA_ENV_NAME}, it comes back with:
/bin/bash: activate: No such file or directory
Not really sure what I am doing wrong here. Can somebody please point me in the right direction?
PS: It works with source $(conda info --root)/etc/profile.d/conda.sh, but I can't really use it since I need to support Windows as well!
Disclaimer: I am new to python/anaconda.