Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .erb/tsconfig.tsbuildinfo

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions src/main/managers/__tests__/ddeManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,15 @@ describe('DdeManager', () => {
);
expect(send).not.toHaveBeenCalled();
});

it('uses the workspace virtual environment python interpreter', () => {
const manager = new DdeManager({ resourcesPath: '/tmp/assets' });

const pythonCommand = (
manager as unknown as { getPythonCommand: () => string }
).getPythonCommand();

expect(pythonCommand).toContain('.venv');
expect(pythonCommand).toContain('python');
});
Comment thread
DmitryMK marked this conversation as resolved.
});
103 changes: 74 additions & 29 deletions src/main/managers/ddeManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,53 @@ class DdeManager {
if (env?.DDE_PYTHON_EXE) {
return env.DDE_PYTHON_EXE;
}

const workspaceVenvPath = path.join(
'/home/nogi/nogi/data-definition-engine-ui',
'.venv',
);
Comment thread
DmitryMK marked this conversation as resolved.
const venvPythonPath =
process.platform === 'win32'
? path.join(workspaceVenvPath, 'Scripts', 'python.exe')
: path.join(workspaceVenvPath, 'bin', 'python');

if (fs.existsSync(venvPythonPath)) {
return venvPythonPath;
}

return process.platform === 'win32' ? 'python' : 'python3';
}

private getPythonEnv(env?: Record<string, string | undefined>) {
const pythonEnv = {
...process.env,
...env,
CDISC_API_KEY: env?.CDISC_API_KEY || process.env.CDISC_API_KEY,
} as Record<string, string | undefined>;

const workspaceVenvPath = path.join(
'/home/nogi/nogi/data-definition-engine-ui',
'.venv',
);
const venvBinPath =
process.platform === 'win32'
? path.join(workspaceVenvPath, 'Scripts')
: path.join(workspaceVenvPath, 'bin');
const venvPythonPath =
process.platform === 'win32'
? path.join(venvBinPath, 'python.exe')
: path.join(venvBinPath, 'python');

if (fs.existsSync(venvPythonPath)) {
pythonEnv.VIRTUAL_ENV = workspaceVenvPath;
pythonEnv.PATH = [venvBinPath, pythonEnv.PATH || '']
.filter(Boolean)
.join(path.delimiter);
}

return pythonEnv;
}

private getScriptPath(step: DdeRunRequest['step']) {
if (step === 'step1' || step === 'step2') {
return path.join(
Expand Down Expand Up @@ -73,11 +117,7 @@ class DdeManager {
const definePath = request.step === 'step3' ? outputPath : undefined;
const child = spawn(pythonCommand, [scriptPath, ...request.args], {
cwd: path.dirname(scriptPath),
env: {
...process.env,
...request.env,
CDISC_API_KEY: request.env?.CDISC_API_KEY || process.env.CDISC_API_KEY,
},
env: this.getPythonEnv(request.env),
});

this.runningProcesses.set(request.id, {
Expand Down Expand Up @@ -178,33 +218,38 @@ class DdeManager {
].join('; ');

return new Promise((resolve) => {
execFile(pythonCommand, ['-c', script], (error, stdout, stderr) => {
if (error) {
execFile(
pythonCommand,
['-c', script],
{ env: this.getPythonEnv() },
(error, stdout, stderr) => {
if (error) {
resolve({
ok: false,
pythonCommand,
version: null,
missingModules: [],
error: stderr.trim() || error.message,
});
return;
}

const [versionLine = '', missingLine = ''] = stdout
.trim()
.split(/\r?\n/);
const missingModules = missingLine
? missingLine.split('|').filter(Boolean)
: [];

resolve({
ok: false,
ok: missingModules.length === 0,
pythonCommand,
version: null,
missingModules: [],
error: stderr.trim() || error.message,
version: versionLine || null,
missingModules,
error: null,
});
return;
}

const [versionLine = '', missingLine = ''] = stdout
.trim()
.split(/\r?\n/);
const missingModules = missingLine
? missingLine.split('|').filter(Boolean)
: [];

resolve({
ok: missingModules.length === 0,
pythonCommand,
version: versionLine || null,
missingModules,
error: null,
});
});
},
);
});
};
}
Expand Down
59 changes: 37 additions & 22 deletions src/renderer/components/DdeExecution/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,32 @@ const styles = {
card: {
borderRadius: 3,
},
logBox: {
logBox: (fullHeight: boolean) => ({
fontFamily: 'Roboto Mono, monospace',
fontSize: 13,
lineHeight: 1.5,
backgroundColor: 'grey.950',
color: 'grey.100',
color: 'grey.700',
borderRadius: 2,
p: 2,
minHeight: 180,
maxHeight: 320,
maxHeight: fullHeight ? '100%' : 320,
height: fullHeight ? '100%' : 'auto',
overflow: 'auto',
whiteSpace: 'pre-wrap',
},
flex: fullHeight ? 1 : 'auto',
}),
};

const DdeExecution: React.FC = () => {
interface DdeExecutionProps {
hideActions?: boolean;
fullHeight?: boolean;
}

const DdeExecution: React.FC<DdeExecutionProps> = ({
hideActions = false,
fullHeight = false,
}) => {
const dispatch = useAppDispatch();
const { apiService } = useContext(AppContext);
const run = useAppSelector((state) => state.dde.run);
Expand All @@ -43,7 +53,6 @@ const DdeExecution: React.FC = () => {

useEffect(() => {
if (!startedAt || !['starting', 'running'].includes(runStatus)) {
setElapsedMs(0);
return undefined;
}
Comment thread
DmitryMK marked this conversation as resolved.

Expand Down Expand Up @@ -100,9 +109,9 @@ const DdeExecution: React.FC = () => {
};

return (
<Card sx={styles.card}>
<CardContent>
<Stack spacing={2}>
<Card sx={{ ...styles.card, height: fullHeight ? '100%' : 'auto' }}>
<CardContent sx={{ height: fullHeight ? '100%' : 'auto' }}>
<Stack spacing={2} sx={{ height: fullHeight ? '100%' : 'auto' }}>
<Stack direction="row" spacing={1} sx={{ alignItems: 'center' }}>
<Typography variant="h6">Execution</Typography>
<Chip
Expand All @@ -116,23 +125,29 @@ const DdeExecution: React.FC = () => {
{run.outputPath ? (
<Alert severity="info">Output: {run.outputPath}</Alert>
) : null}
<Box sx={styles.logBox}>
<Box sx={styles.logBox(fullHeight)}>
{run.lines.length > 0
? run.lines.join('\n')
: 'Waiting for process output...'}
</Box>
<Stack direction="row" spacing={1}>
{['starting', 'running'].includes(run.status) ? (
<Button variant="contained" color="error" onClick={handleCancel}>
Cancel
</Button>
) : null}
{run.status !== 'running' && run.status !== 'starting' ? (
<Button variant="text" onClick={handleClear}>
Clear
</Button>
) : null}
</Stack>
{!hideActions ? (
<Stack direction="row" spacing={1}>
{['starting', 'running'].includes(run.status) ? (
<Button
variant="contained"
color="error"
onClick={handleCancel}
>
Cancel
</Button>
) : null}
{run.status !== 'running' && run.status !== 'starting' ? (
<Button variant="text" onClick={handleClear}>
Clear
</Button>
) : null}
</Stack>
) : null}
</Stack>
</CardContent>
</Card>
Expand Down
Loading