Skip to content

Commit

Permalink
Merge pull request #66 from railwayapp/jr/support-python-27
Browse files Browse the repository at this point in the history
Support Python 2.7
  • Loading branch information
coffee-cup authored May 6, 2022
2 parents caa814a + 5ff30d8 commit 6706962
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 24 deletions.
1 change: 1 addition & 0 deletions examples/python-2/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2.7
1 change: 1 addition & 0 deletions examples/python-2/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print "Hello from Python 2"
9 changes: 2 additions & 7 deletions src/nixpacks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,13 +216,8 @@ impl<'a> AppBuilder<'a> {
let env_var_pkgs = self
.environment
.get_config_variable("PKGS")
.map(|pkg_string| {
pkg_string
.split(" ")
.map(|s| Pkg::new(s))
.collect::<Vec<_>>()
})
.unwrap_or(Vec::new());
.map(|pkg_string| pkg_string.split(' ').map(Pkg::new).collect::<Vec<_>>())
.unwrap_or_default();

// Add custom user packages
let mut pkgs = [self.options.custom_pkgs.clone(), env_var_pkgs].concat();
Expand Down
2 changes: 1 addition & 1 deletion src/providers/npm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ impl NpmProvider {
.as_ref()
.and_then(|engines| engines.get("node"));

let node_version = env_node_version.or(pkg_node_version);
let node_version = pkg_node_version.or(env_node_version);

let node_version = match node_version {
Some(node_version) => node_version,
Expand Down
102 changes: 88 additions & 14 deletions src/providers/python.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::collections::HashMap;

use anyhow::{Context, Result};
use anyhow::{bail, Context, Result};

use serde::Deserialize;

use crate::{
Expand All @@ -15,7 +16,10 @@ use crate::{

use super::Provider;

pub const DEFAULT_PYTHON_PKG_NAME: &'static &str = &"python38";

pub struct PythonProvider {}

impl Provider for PythonProvider {
fn name(&self) -> &str {
"python"
Expand All @@ -27,12 +31,9 @@ impl Provider for PythonProvider {
|| app.includes_file("pyproject.toml"))
}

fn setup(
&self,
_app: &App,
_env: &crate::nixpacks::environment::Environment,
) -> Result<Option<SetupPhase>> {
Ok(Some(SetupPhase::new(vec![Pkg::new("python38")])))
fn setup(&self, app: &App, env: &Environment) -> Result<Option<SetupPhase>> {
let pkg = PythonProvider::get_nix_python_package(app, env)?;
Ok(Some(SetupPhase::new(vec![pkg])))
}

fn install(&self, app: &App, _env: &Environment) -> Result<Option<InstallPhase>> {
Expand Down Expand Up @@ -63,7 +64,7 @@ impl Provider for PythonProvider {

fn start(&self, app: &App, _env: &Environment) -> Result<Option<StartPhase>> {
if app.includes_file("pyproject.toml") {
if let Ok(meta) = self.parse_pyproject(app) {
if let Ok(meta) = PythonProvider::parse_pyproject(app) {
if let Some(entry_point) = meta.entry_point {
return Ok(Some(StartPhase::new(match entry_point {
EntryPoint::Command(cmd) => cmd,
Expand Down Expand Up @@ -110,7 +111,30 @@ enum EntryPoint {
}

impl PythonProvider {
fn read_pyproject(&self, app: &App) -> Result<Option<PyProject>> {
fn get_nix_python_package(app: &App, env: &Environment) -> Result<Pkg> {
let mut custom_version = env
.get_config_variable("PYTHON_VERSION")
.map(|s| s.to_string());

if custom_version.is_none() && app.includes_file(".python-version") {
custom_version = Some(app.read_file(".python-version")?);
}

match custom_version.map(|s| s.trim().to_string()) {
Some(custom_version) => {
if custom_version == "2" || custom_version == "2.7" {
Ok(Pkg::new("python27Full"))
} else if custom_version == "3" || custom_version == "3.8" {
Ok(Pkg::new(DEFAULT_PYTHON_PKG_NAME))
} else {
bail!("Only the latest version of Python `2` or `3` are supported.")
}
}
None => Ok(Pkg::new(DEFAULT_PYTHON_PKG_NAME)),
}
}

fn read_pyproject(app: &App) -> Result<Option<PyProject>> {
if app.includes_file("pyproject.toml") {
return Ok(Some(
app.read_toml("pyproject.toml")
Expand All @@ -119,7 +143,8 @@ impl PythonProvider {
}
Ok(None)
}
fn parse_project(&self, project: &PyProject) -> ProjectMeta {

fn parse_project(project: &PyProject) -> ProjectMeta {
let project_name = project
.project
.as_ref()
Expand Down Expand Up @@ -148,11 +173,60 @@ impl PythonProvider {
entry_point,
}
}
fn parse_pyproject(&self, app: &App) -> Result<ProjectMeta> {
Ok(self.parse_project(
&(self
.read_pyproject(app)?

fn parse_pyproject(app: &App) -> Result<ProjectMeta> {
Ok(PythonProvider::parse_project(
&(PythonProvider::read_pyproject(app)?
.ok_or_else(|| anyhow::anyhow!("failed to load pyproject.toml"))?),
))
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::nixpacks::{app::App, environment::Environment, nix::Pkg};
use std::collections::HashMap;

#[test]
fn test_no_version() -> Result<()> {
assert_eq!(
PythonProvider::get_nix_python_package(
&App::new("./examples/python")?,
&Environment::default()
)?,
Pkg::new(DEFAULT_PYTHON_PKG_NAME)
);

Ok(())
}

#[test]
fn test_custom_version() -> Result<()> {
assert_eq!(
PythonProvider::get_nix_python_package(
&App::new("./examples/python-2")?,
&Environment::default()
)?,
Pkg::new("python27Full")
);

Ok(())
}

#[test]
fn test_version_from_environment_variable() -> Result<()> {
assert_eq!(
PythonProvider::get_nix_python_package(
&App::new("./examples/python")?,
&Environment::new(HashMap::from([(
"NIXPACKS_PYTHON_VERSION".to_string(),
"2.7".to_string()
)]))
)?,
Pkg::new("python27Full")
);

Ok(())
}
}
11 changes: 9 additions & 2 deletions tests/docker_run_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn get_container_ids_from_image(image: String) -> String {
String::from_utf8_lossy(&output.stdout).to_string()
}

fn stop_containers(container_id: &String) {
fn stop_containers(container_id: &str) {
Command::new("docker")
.arg("stop")
.arg(container_id)
Expand All @@ -31,7 +31,7 @@ fn stop_containers(container_id: &String) {
.expect("failed to execute docker stop");
}

fn remove_containers(container_id: &String) {
fn remove_containers(container_id: &str) {
Command::new("docker")
.arg("rm")
.arg(container_id)
Expand Down Expand Up @@ -145,6 +145,13 @@ fn test_python() {
assert!(output.contains("Hello from Python"));
}

#[test]
fn test_python_2() {
let name = simple_build("./examples/python-2");
let output = run_image(name);
assert!(output.contains("Hello from Python 2"));
}

#[test]
fn test_deno() {
let name = simple_build("./examples/deno");
Expand Down

0 comments on commit 6706962

Please sign in to comment.