diff --git a/examples/python/Procfile b/examples/python/Procfile new file mode 100644 index 000000000..19452012e --- /dev/null +++ b/examples/python/Procfile @@ -0,0 +1 @@ +web: gunicorn main:app diff --git a/src/nixpacks/mod.rs b/src/nixpacks/mod.rs index 02dc101ff..b799c12c9 100644 --- a/src/nixpacks/mod.rs +++ b/src/nixpacks/mod.rs @@ -428,6 +428,12 @@ impl<'a> AppBuilder<'a> { .map(|cmd| format!("RUN {}", cmd)) .unwrap_or_else(|| "".to_string()); + let path_env = if let Some(paths) = install_phase.paths { + format!("ENV PATH {}:$PATH", paths.join(":")) + } else { + "".to_string() + }; + // Files to copy for install phase // If none specified, copy over the entire app let install_files = install_phase @@ -500,6 +506,7 @@ impl<'a> AppBuilder<'a> { # Install {install_copy_cmd} {install_cmd} + {path_env} # Build {build_copy_cmd} @@ -514,6 +521,7 @@ impl<'a> AppBuilder<'a> { args_string=args_string, install_copy_cmd=get_copy_command(&install_files, app_dir), install_cmd=install_cmd, + path_env=path_env, build_copy_cmd=get_copy_command(&build_files, app_dir), build_cmd=build_cmd, start_copy_cmd=get_copy_command(&start_files, app_dir), diff --git a/src/nixpacks/phase.rs b/src/nixpacks/phase.rs index d769bfa08..0520a87a1 100644 --- a/src/nixpacks/phase.rs +++ b/src/nixpacks/phase.rs @@ -46,6 +46,8 @@ pub struct InstallPhase { #[serde(rename = "onlyIncludeFiles")] pub only_include_files: Option>, + + pub paths: Option>, } impl InstallPhase { @@ -53,6 +55,7 @@ impl InstallPhase { Self { cmd: Some(cmd), only_include_files: None, + paths: None, } } @@ -64,6 +67,15 @@ impl InstallPhase { self.only_include_files = Some(vec![file]); } } + + pub fn add_path(&mut self, path: String) { + if let Some(mut paths) = self.paths.clone() { + paths.push(path); + self.paths = Some(paths); + } else { + self.paths = Some(vec![path]); + } + } } #[serde_with::skip_serializing_none] diff --git a/src/providers/python.rs b/src/providers/python.rs index 409aa1f7c..915a2c6ba 100644 --- a/src/providers/python.rs +++ b/src/providers/python.rs @@ -36,17 +36,28 @@ impl Provider for PythonProvider { } fn install(&self, app: &App, _env: &Environment) -> Result> { + let env_loc = "/opt/venv"; + let create_env = format!("python -m venv {}", env_loc); + let activate_env = format!(". {}/bin/activate", env_loc); + if app.includes_file("requirements.txt") { - let mut install_phase = InstallPhase::new( - "python -m ensurepip && python -m pip install -r requirements.txt".to_string(), - ); + let mut install_phase = InstallPhase::new(format!( + "{} && {} && pip install -r requirements.txt", + create_env, activate_env + )); install_phase.add_file_dependency("requirements.txt".to_string()); + install_phase.add_path(format!("{}/bin", env_loc)); return Ok(Some(install_phase)); } else if app.includes_file("pyproject.toml") { - let mut install_phase =InstallPhase::new("python -m ensurepip && python -m pip install --upgrade build setuptools && python -m pip install .".to_string()); + let mut install_phase = InstallPhase::new(format!( + "{} && {} && pip install --upgrade build setuptools && pip install .", + create_env, activate_env + )); install_phase.add_file_dependency("pyproject.toml".to_string()); + install_phase.add_path(format!("{}/bin", env_loc)); return Ok(Some(install_phase)); } + Ok(None) }