Skip to content

Commit

Permalink
Merge branch 'main' into milo/spa-provider
Browse files Browse the repository at this point in the history
  • Loading branch information
Milo123459 authored Jan 14, 2025
2 parents 48be44a + f12b6d2 commit ea1b4d9
Show file tree
Hide file tree
Showing 18 changed files with 249 additions and 65 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "nixpacks"
version = "1.30.0"
version = "1.31.0"
edition = "2021"
license = "MIT"
authors = ["Railway <contact@railway.app>"]
Expand Down
5 changes: 0 additions & 5 deletions examples/lunatic-basic/.cargo/config.toml

This file was deleted.

10 changes: 0 additions & 10 deletions examples/lunatic-basic/Cargo.toml

This file was deleted.

21 changes: 0 additions & 21 deletions examples/lunatic-basic/src/main.rs

This file was deleted.

30 changes: 30 additions & 0 deletions examples/python-psycopg2/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import os
import psycopg2
from psycopg2 import Error
import time

def get_db_connection():
max_retries = 3
retry_delay = 2 # seconds

for attempt in range(max_retries):
try:
connection = psycopg2.connect(
host=os.getenv('PGHOST'),
database=os.getenv('PGDATABASE'),
user=os.getenv('PGUSER'),
password=os.getenv('PGPASSWORD'),
port=os.getenv('PGPORT')
)
return connection
except Error as e:
if "starting up" in str(e).lower():
if attempt < max_retries - 1: # Don't sleep on last attempt
time.sleep(retry_delay)
continue
print(f"Error connecting to PostgreSQL: {e}")
return None

def close_connection(connection):
if connection:
connection.close()
83 changes: 83 additions & 0 deletions examples/python-psycopg2/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from database import get_db_connection, close_connection

def create_table():
connection = get_db_connection()
if connection:
try:
cursor = connection.cursor()

# Create a sample table
create_table_query = '''
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL
)
'''
cursor.execute(create_table_query)

# Commit the changes
connection.commit()
print("Table created successfully")

except Exception as e:
print(f"Error: {e}")
finally:
cursor.close()
close_connection(connection)

def insert_user(name, email):
connection = get_db_connection()
if connection:
try:
cursor = connection.cursor()

# Insert a new user
insert_query = '''
INSERT INTO users (name, email)
VALUES (%s, %s)
RETURNING id
'''
cursor.execute(insert_query, (name, email))
user_id = cursor.fetchone()[0]

# Commit the changes
connection.commit()
print(f"User inserted successfully with ID: {user_id}")

except Exception as e:
print(f"Error: {e}")
finally:
cursor.close()
close_connection(connection)

def get_all_users():
connection = get_db_connection()
if connection:
try:
cursor = connection.cursor()

# Select all users
select_query = "SELECT * FROM users"
cursor.execute(select_query)
users = cursor.fetchall()

for user in users:
print(f"ID: {user[0]}, Name: {user[1]}, Email: {user[2]}")

except Exception as e:
print(f"Error: {e}")
finally:
cursor.close()
close_connection(connection)

if __name__ == "__main__":
# Create the table
create_table()

# Insert some sample users
insert_user("John Doe", "john@example.com")
insert_user("Jane Smith", "jane@example.com")

# Retrieve and display all users
get_all_users()
1 change: 1 addition & 0 deletions examples/python-psycopg2/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
psycopg2-binary>=2.9.10
2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
let
package = with nixpkgs; rustPlatform.buildRustPackage {
pname = "nixpacks";
version = "1.30.0";
version = "1.31.0";
src = ./.;
cargoLock = {
lockFile = ./Cargo.lock;
Expand Down
30 changes: 26 additions & 4 deletions src/providers/node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -673,14 +673,18 @@ fn parse_node_version_into_pkg(node_version: &str) -> String {
eprintln!("Warning: node version {node_version} is not valid, using default node version {default_node_pkg_name}");
Range::parse(DEFAULT_NODE_VERSION.to_string()).unwrap()
});
let mut available_node_versions = AVAILABLE_NODE_VERSIONS.to_vec();
let mut available_lts_node_versions = AVAILABLE_NODE_VERSIONS
.iter()
.filter(|v| *v % 2 == 0)
.collect::<Vec<_>>();

// use newest node version first
available_node_versions.sort_by(|a, b| b.cmp(a));
for version_number in available_node_versions {
available_lts_node_versions.sort_by(|a, b| b.cmp(a));
for version_number in available_lts_node_versions {
let version_range_string = format!("{version_number}.x.x");
let version_range: Range = version_range_string.parse().unwrap();
if version_range.allows_any(&range) {
return version_number_to_pkg(version_number);
return version_number_to_pkg(*version_number);
}
}
default_node_pkg_name
Expand Down Expand Up @@ -760,6 +764,24 @@ mod test {
Ok(())
}

#[test]
fn test_latest_lts_version() -> Result<()> {
assert_eq!(
NodeProvider::get_nix_node_pkg(
&PackageJson {
name: Some(String::default()),
engines: Some(engines_node(">=18")),
..Default::default()
},
&App::new("examples/node")?,
&Environment::default()
)?,
Pkg::new(version_number_to_pkg(22).as_str())
);

Ok(())
}

#[test]
fn test_simple_engine() -> Result<()> {
assert_eq!(
Expand Down
11 changes: 4 additions & 7 deletions src/providers/python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,18 +160,15 @@ enum EntryPoint {

impl PythonProvider {
fn setup(&self, app: &App, env: &Environment) -> Result<Option<Phase>> {
let mut setup = Phase::setup(None);

let mut pkgs: Vec<Pkg> = vec![];
let (python_base_package, nix_archive) = PythonProvider::get_nix_python_package(app, env)?;

pkgs.append(&mut vec![python_base_package]);

if PythonProvider::is_using_postgres(app, env)? {
// Postgres requires postgresql and gcc on top of the original python packages

// .dev variant is required in order for pg_config to be available, which is needed by psycopg2
// the .dev variant requirement is caused by this change in nix pkgs:
// https://github.com/NixOS/nixpkgs/blob/43eac3c9e618c4114a3441b52949609ea2104670/pkgs/servers/sql/postgresql/pg_config.sh
pkgs.append(&mut vec![Pkg::new("postgresql.dev")]);
pkgs.append(&mut vec![Pkg::new("postgresql_16.dev")]);
}

if PythonProvider::is_django(app, env)? && PythonProvider::is_using_mysql(app, env)? {
Expand All @@ -183,7 +180,7 @@ impl PythonProvider {
pkgs.append(&mut vec![Pkg::new("pipenv")]);
}

let mut setup = Phase::setup(Some(pkgs));
setup.add_nix_pkgs(&pkgs);
setup.set_nix_archive(nix_archive);

if PythonProvider::uses_dep(app, "cairo")? {
Expand Down
4 changes: 4 additions & 0 deletions src/providers/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const CARGO_GIT_CACHE_DIR: &str = "/root/.cargo/git";
const CARGO_REGISTRY_CACHE_DIR: &str = "/root/.cargo/registry";
const CARGO_TARGET_CACHE_DIR: &str = "target";

const NIX_ARCHIVE: &str = "ef56e777fedaa4da8c66a150081523c5de1e0171";

pub struct RustProvider {}

impl Provider for RustProvider {
Expand Down Expand Up @@ -76,6 +78,8 @@ impl RustProvider {
setup.add_nix_pkgs(&[Pkg::new("musl"), Pkg::new("musl.dev")]);
}

setup.set_nix_archive(NIX_ARCHIVE.to_string());

Ok(setup)
}

Expand Down
49 changes: 42 additions & 7 deletions tests/docker_run_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,48 @@ async fn test_python_asdf_poetry() {
assert!(output.contains("Poetry (version 1.8.2)"), "{}", output);
}

#[tokio::test]
async fn test_python_psycopg2() -> Result<()> {
// Create the network
let n = create_network();
let network_name = n.name.clone();

// Create the postgres instance
let c = run_postgres();
let container_name = c.name.clone();

// Attach the postgres instance to the network
attach_container_to_network(n.name, container_name.clone());

let name = match simple_build("./examples/python-psycopg2").await {
Ok(name) => name,
Err(err) => {
// Cleanup containers and networks, and then error
stop_and_remove_container(container_name);
remove_network(network_name);
return Err(err);
}
};

let output = run_image(
&name,
Some(Config {
environment_variables: c.config.unwrap().environment_variables,
network: Some(network_name.clone()),
}),
)
.await;

println!("OUTPUT = {}", output);

// Cleanup containers and networks
stop_and_remove_container(container_name);
remove_network(network_name);

assert!(output.contains("User inserted successfully with ID"));
Ok(())
}

#[tokio::test]
async fn test_django() -> Result<()> {
// Create the network
Expand Down Expand Up @@ -1018,13 +1060,6 @@ async fn test_django_mysql() -> Result<()> {
Ok(())
}

#[tokio::test]
async fn test_lunatic_basic() {
let name = simple_build("./examples/lunatic-basic").await.unwrap();
let output = run_image(&name, None).await;
assert!(output.contains("PING-PONG"));
}

#[tokio::test]
async fn test_python_poetry() {
let name = simple_build("./examples/python-poetry").await.unwrap();
Expand Down
3 changes: 1 addition & 2 deletions tests/snapshots/generate_plan_tests__node_pnpm_corepack.snap
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
---
source: tests/generate_plan_tests.rs
expression: plan
snapshot_kind: text
---
{
"providers": [],
Expand Down Expand Up @@ -44,7 +43,7 @@ snapshot_kind: text
"setup": {
"name": "setup",
"nixPkgs": [
"nodejs_23",
"nodejs_22",
"pnpm-9_x"
],
"nixOverlays": [
Expand Down
3 changes: 1 addition & 2 deletions tests/snapshots/generate_plan_tests__node_turborepo.snap
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
---
source: tests/generate_plan_tests.rs
expression: plan
snapshot_kind: text
---
{
"providers": [],
Expand Down Expand Up @@ -45,7 +44,7 @@ snapshot_kind: text
"setup": {
"name": "setup",
"nixPkgs": [
"nodejs_23",
"nodejs_22",
"npm-8_x"
],
"nixOverlays": [
Expand Down
3 changes: 1 addition & 2 deletions tests/snapshots/generate_plan_tests__python_django.snap
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
---
source: tests/generate_plan_tests.rs
expression: plan
snapshot_kind: text
---
{
"providers": [],
Expand Down Expand Up @@ -36,7 +35,7 @@ snapshot_kind: text
"name": "setup",
"nixPkgs": [
"python3",
"postgresql.dev",
"postgresql_16.dev",
"gcc"
],
"nixLibs": [
Expand Down
Loading

0 comments on commit ea1b4d9

Please sign in to comment.