Skip to content

Commit 79cd4fe

Browse files
authored
Start local dev automation (#1050)
1 parent b4ea9c5 commit 79cd4fe

File tree

6 files changed

+299
-15
lines changed

6 files changed

+299
-15
lines changed

packages/cargo-pgml-components/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/cargo-pgml-components/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cargo-pgml-components"
3-
version = "0.1.17"
3+
version = "0.1.18-alpha.1"
44
edition = "2021"
55
authors = ["PostgresML <team@postgresml.org>"]
66
license = "MIT"

packages/cargo-pgml-components/src/frontend/tools.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,7 @@ pub fn install() {
3434
}
3535

3636
for plugin in ROLLUP_PLUGINS {
37-
if execute_with_nvm(
38-
Command::new("npm")
39-
.arg("list")
40-
.arg("-g")
41-
.arg(plugin)
42-
)
43-
.is_err()
44-
{
37+
if execute_with_nvm(Command::new("npm").arg("list").arg("-g").arg(plugin)).is_err() {
4538
warn(&format!("installing rollup plugin {}", plugin));
4639
unwrap_or_exit!(execute_with_nvm(
4740
Command::new("npm").arg("install").arg("-g").arg(plugin)
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
//! So special, it deserves its own file.
2+
//!
3+
//! Code to handle the setup of our pretty complex local development
4+
//! environment.
5+
6+
use crate::util::{execute_command, info, ok_or_error, print, psql_output, unwrap_or_exit, warn};
7+
use std::process::Command;
8+
9+
#[cfg(target_os = "macos")]
10+
static PG_INSTALL: &str = "
11+
Install PostgreSQL with brew:\n
12+
\tbrew install postgresql@15
13+
";
14+
15+
#[cfg(target_os = "linux")]
16+
static PG_INSTALL: &str = "
17+
Install PostgreSQL with Aptitude:\n
18+
\tsudo apt install postgresql
19+
";
20+
21+
#[cfg(target_os = "macos")]
22+
static BUILD_ESSENTIAL: &str = "
23+
Install build tools with Aptitude:\n
24+
\txcode-select --install
25+
";
26+
27+
#[cfg(target_os = "linux")]
28+
static BUILD_ESSENTIAL: &str = "
29+
Install build tools with Aptitude:\n
30+
\tsudo apt install build-essential
31+
";
32+
33+
#[cfg(target_os = "macos")]
34+
static PG_PG_STAT_STATEMENTS: &str = "
35+
To install pg_stat_statements into your database:
36+
37+
1. Create the extension in PostgreSQL:\n
38+
\tpsql -d postgres -c 'CREATE EXTENSION pg_stat_statements'
39+
2. Add pg_stat_statements into your shared_preload_libraries:\n
40+
\tpsql -c 'ALTER SYSTEM SET shared_preload_libraries TO pgml,pg_stat_statements'
41+
3. Restart PostgreSQL:\n
42+
\tbrew service restart postgresql@15
43+
";
44+
45+
#[cfg(target_os = "linux")]
46+
static PG_PG_STAT_STATEMENTS: &str = "
47+
To install pg_stat_statements into your database:
48+
49+
1. Create the extension in PostgreSQL:\n
50+
\tpsql -d postgres -c 'CREATE EXTENSION pg_stat_statements'
51+
2. Add pg_stat_statements into your shared_preload_libraries:\n
52+
\tpsql -c 'ALTER SYSTEM SET shared_preload_libraries TO pgml,pg_stat_statements'
53+
3. Restart PostgreSQL:\n
54+
\tsudo service postgresql restart
55+
";
56+
57+
#[cfg(target_os = "macos")]
58+
static PG_PGVECTOR: &str = "Install pgvector into your PostgreSQL database:\n
59+
\tgit clone --branch v0.5.0 https://github.com/pgvector/pgvector && \\
60+
\tcd pgvector && \\
61+
\techo \"trusted = true\" >> vector.control && \\
62+
\tmake && \\
63+
\tmake install
64+
";
65+
66+
#[cfg(target_os = "linux")]
67+
static PG_PGVECTOR: &str = "Install pgvector into your PostgreSQL database:\n
68+
\tgit clone --branch v0.5.0 https://github.com/pgvector/pgvector && \\
69+
\tcd pgvector && \\
70+
\techo \"trusted = true\" >> vector.control && \\
71+
\tmake && \\
72+
\tsudo make install
73+
";
74+
75+
#[cfg(target_os = "macos")]
76+
static PG_PGML: &str = "To install PostgresML into your PostgreSQL database,
77+
follow the instructions on:
78+
79+
\thttps://postgresml.org/docs/guides/setup/v2/installation
80+
";
81+
82+
#[cfg(target_os = "linux")]
83+
static PG_PGML: &str = "To install PostgresML
84+
into your PostgreSQL database:
85+
86+
1. Add your Aptitude repository into your sources:
87+
88+
\techo \"deb [trusted=yes] https://apt.postgresml.org $(lsb_release -cs) main\" | \\
89+
\tsudo tee -a /etc/apt/sources.list
90+
91+
2. Update Aptitude:
92+
93+
\tsudo apt update
94+
95+
3. Install PostgresML:
96+
97+
\tsudo apt install postgresml-14
98+
";
99+
100+
fn postgres_running() -> String {
101+
let whoami = unwrap_or_exit!(execute_command(&mut Command::new("whoami")));
102+
103+
let running = format!(
104+
"
105+
Could not connect to PostgreSQL database 'postgres' with psql.\n
106+
Is PostgreSQL running and accepting connections?
107+
"
108+
);
109+
110+
#[cfg(target_os = "macos")]
111+
let start = format!(
112+
"
113+
To start PostgreSQL, run:\n
114+
\tbrew service start postgresql@15
115+
"
116+
);
117+
118+
#[cfg(target_os = "linux")]
119+
let start = format!(
120+
"
121+
To start PostgreSQL, run:\n
122+
\tsudo service postgresql start
123+
"
124+
);
125+
126+
let user = format!(
127+
"
128+
If PostgreSQL is already running, your current UNIX user is
129+
not allowed to connect to the 'postgres' database with psql
130+
using a UNIX socket.
131+
132+
To make sure your user is allowed to connect:
133+
134+
1. Create the role:\n
135+
\tcreaterole --superuser --login {whoami}
136+
137+
2. Create the user's database:\n
138+
\t createdb {whoami}
139+
"
140+
);
141+
142+
running + &start + &user
143+
}
144+
145+
fn dependencies() -> anyhow::Result<()> {
146+
ok_or_error!(
147+
"checking for psql",
148+
{ execute_command(Command::new("which").arg("psql")).is_ok() },
149+
PG_INSTALL
150+
);
151+
152+
ok_or_error!(
153+
"checking for build tools",
154+
{ execute_command(Command::new("which").arg("gcc")).is_ok() },
155+
BUILD_ESSENTIAL
156+
);
157+
158+
ok_or_error!(
159+
"checking for PostgreSQL connectivity",
160+
{
161+
if let Err(err) = psql_output("SELECT version()") {
162+
error!("{}", err);
163+
false
164+
} else {
165+
true
166+
}
167+
},
168+
postgres_running()
169+
);
170+
171+
ok_or_error!(
172+
"checking for pgvector PostgreSQL extension",
173+
{
174+
let output = psql_output(
175+
"
176+
SELECT
177+
name
178+
FROM
179+
pg_available_extensions
180+
WHERE name = 'vector'
181+
",
182+
)?;
183+
output.contains("vector")
184+
},
185+
PG_PGVECTOR
186+
);
187+
188+
ok_or_error!(
189+
"checking for pgml PostgreSQL extension",
190+
{
191+
let output_installed = psql_output(
192+
"
193+
SELECT
194+
name
195+
FROM
196+
pg_available_extensions
197+
WHERE name = 'pgml'
198+
",
199+
)?;
200+
201+
let output_shared = psql_output("SHOW shared_preload_libraries")?;
202+
203+
output_installed.contains("pgml") && output_shared.contains("pgml")
204+
},
205+
PG_PGML
206+
);
207+
208+
ok_or_error!(
209+
"checking for pg_stat_statements PostgreSQL extension",
210+
{
211+
let output_installed = psql_output("SHOW shared_preload_libraries")?;
212+
let output_running = psql_output("SELECT * FROM pg_stat_statements LIMIT 1");
213+
output_installed.contains("pg_stat_statements") && output_running.is_ok()
214+
},
215+
PG_PG_STAT_STATEMENTS
216+
);
217+
218+
print("checking for dashboard database...");
219+
let output = psql_output(
220+
"SELECT datname FROM pg_database WHERE datname = 'pgml_dashboard_development'",
221+
)?;
222+
if !output.contains("pgml_dashboard_development") {
223+
warn("missing");
224+
print("creating pgml_dashboard_development database...");
225+
unwrap_or_exit!(execute_command(
226+
Command::new("createdb").arg("pgml_dashboard_development")
227+
));
228+
info("ok");
229+
print("creating vector extension in pgml_dashboard_development...");
230+
unwrap_or_exit!(execute_command(
231+
Command::new("psql")
232+
.arg("-c")
233+
.arg("CREATE EXTENSION IF NOT EXISTS vector")
234+
.arg("pgml_dashboard_development")
235+
));
236+
info("ok");
237+
print("creating pgml extension in pgml_dashboard_development...");
238+
unwrap_or_exit!(execute_command(
239+
Command::new("psql")
240+
.arg("-c")
241+
.arg("CREATE EXTENSION IF NOT EXISTS pgml")
242+
.arg("pgml_dashboard_development")
243+
));
244+
info("ok");
245+
} else {
246+
info("ok");
247+
}
248+
249+
info("all dependencies are installed and working");
250+
251+
Ok(())
252+
}
253+
254+
pub fn setup() {
255+
unwrap_or_exit!(dependencies())
256+
}

packages/cargo-pgml-components/src/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ extern crate log;
1111
mod backend;
1212
mod config;
1313
mod frontend;
14+
mod local_dev;
1415
mod util;
1516

1617
use config::Config;
@@ -62,6 +63,9 @@ enum Commands {
6263
/// Add new elements to the project.
6364
#[command(subcommand)]
6465
Add(AddCommands),
66+
67+
/// Setup local dev.
68+
LocalDev {},
6569
}
6670

6771
#[derive(Subcommand, Debug)]
@@ -85,6 +89,7 @@ fn main() {
8589
crate::frontend::components::add(&Path::new(&name), pgml_commands.overwrite)
8690
}
8791
},
92+
Commands::LocalDev {} => local_dev::setup(),
8893
}
8994
}
9095
}

packages/cargo-pgml-components/src/util.rs

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,17 @@ pub fn execute_command(command: &mut Command) -> std::io::Result<String> {
4848
}
4949
};
5050

51-
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
52-
let stdout = String::from_utf8_lossy(&output.stderr).to_string();
51+
let stderr = unwrap_or_exit!(String::from_utf8(output.stderr)).to_string();
52+
let stdout = unwrap_or_exit!(String::from_utf8(output.stdout)).to_string();
5353

5454
if !output.status.success() {
55-
let error = String::from_utf8_lossy(&output.stderr).to_string();
5655
debug!(
5756
"{} failed: {}",
5857
command.get_program().to_str().unwrap(),
59-
error,
58+
stderr,
6059
);
6160

62-
return Err(std::io::Error::new(ErrorKind::Other, error));
61+
return Err(std::io::Error::new(ErrorKind::Other, stderr));
6362
}
6463

6564
if !stderr.is_empty() {
@@ -95,3 +94,34 @@ pub fn compare_strings(string1: &str, string2: &str) -> bool {
9594
// TODO: faster string comparison method needed.
9695
string1.trim() == string2.trim()
9796
}
97+
98+
pub fn psql_output(query: &str) -> std::io::Result<String> {
99+
let mut cmd = Command::new("psql");
100+
cmd.arg("-c").arg(query).arg("-t").arg("-d").arg("postgres");
101+
102+
let output = execute_command(&mut cmd)?;
103+
Ok(output.trim().to_string())
104+
}
105+
106+
pub fn print(s: &str) {
107+
print!("{}", s);
108+
let _ = std::io::stdout().flush();
109+
}
110+
111+
macro_rules! ok_or_error {
112+
($what:expr, $expr:block, $howto:expr) => {{
113+
use std::io::Write;
114+
print!("{}...", $what);
115+
let _ = std::io::stdout().flush();
116+
117+
if $expr {
118+
crate::util::info("ok");
119+
} else {
120+
crate::util::error("error");
121+
println!("{}", $howto);
122+
std::process::exit(1);
123+
}
124+
}};
125+
}
126+
127+
pub(crate) use ok_or_error;

0 commit comments

Comments
 (0)