Skip to content
Open
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 Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ enum_variant_type = "0.3.1"
duct = "1"
evt-trait-object = "0.1.0"
serde = { version = "1.0.160", features = ["derive"] }
figment = { version = "0.10.19", features = ["toml"] }
figment = { version = "0.10.19", features = ["toml", "env"] }
regex = "1.11.1"
lazy_static = "1.5.0"
bollard = "0.20"
Expand Down
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ And others like:
- [.deb file](#deb-file)
- [apt](#apt)
- [AUR repository](#aur-repository)
- [⚙️ Configuration](#-configuration)
- [CLI Source Configuration](#cli-source-configuration)
- [Configuration File](#configuration-file)
- [Environment Variables Override](#environment-variables-override)
- [Resolution order](#resolution-order)
- [🧪 Usage](#-usage)
- [Stop any running project](#stop-any-running-project)
- [Create storage buckets interactively](#create-storage-buckets-interactively)
Expand Down Expand Up @@ -103,6 +108,33 @@ Coming soon


## ⚙️ Configuration

### CLI Source Configuration
Sometimes you want to override the CLI source. Maybe you need a pinned supabase version or `npx` is unavailable.
By default, sbp uses `npx` to invoke the Supabase CLI. This behaviour remains unchanged unless explicitly configured.
#### Configuration File
You can place an `sbp.toml` file in the project directory or your home directory.
Example:
```toml
# See: sbp.toml.example
cli_source = { FromPath = "/usr/local/bin/supabase"}
```
#### Environment Variables Override
You can also configure via environment variables:
```shell
SBP_CLI_SOURCE=FromPath #or Npx
SBP_CLI_PATH="/usr/local/bin/supabase" # required if you decide to use FromPath
```
#### Resolution order
Configuration is resolved in the following order:
1. project `sbp.toml`
2. home `sbp.toml`
3. environment variables `SBP_*`
4. default (`npx`)

So existing setups continue to work unchanged.

## 🧪 Usage

### Stop any running project
Expand Down
1 change: 1 addition & 0 deletions sbp.toml.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cli_source = { FromPath = "/usr/local/bin/supabase" }
4 changes: 3 additions & 1 deletion src/abstraction/supabase/project.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::abstraction::{Migration, MigrationStatus, NO_DOCKER, SupabaseRuntime, containers};
use crate::errors::NoWay;
use crate::CONFIG;

use std::collections::HashSet;
use std::path::PathBuf;
Expand Down Expand Up @@ -102,7 +103,8 @@ impl SupabaseProject {
}

pub fn runtime(&self) -> SupabaseRuntime<'_> {
SupabaseRuntime { project: &self }
let cli_source = &CONFIG.cli_source;
SupabaseRuntime { project: &self, cli_source }
}

pub fn migrations_dir(&self) -> PathBuf {
Expand Down
24 changes: 22 additions & 2 deletions src/abstraction/supabase/runtime.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
use std::fmt;
use std::process::{Output, Stdio};
use std::fmt::Formatter;

use anyhow::Context;
use duct::cmd;
use serde::{Deserialize, Serialize};
use tokio::process::Command;
use tokio_postgres::{Client, NoTls, Row, ToStatement, types::ToSql};

use crate::{abstraction::SupabaseProject, utils::escape_for_sh_double_quotes};

#[derive(Deserialize, Serialize, Debug)]
pub enum CliSource {
Npx,
FromPath(std::path::PathBuf),
}

impl fmt::Display for CliSource {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
CliSource::Npx => write!(f,"npx --yes --loglevel=error supabase@latest"),
CliSource::FromPath(path) => write!(f,"{}", path.display())
}
}
}

pub struct SupabaseRuntime<'a> {
pub project: &'a SupabaseProject,
pub cli_source: &'static CliSource,
}

impl SupabaseRuntime<'_> {
Expand Down Expand Up @@ -120,7 +139,8 @@ Then re-run the command.",
self.validate().await?;

let full_command = format!(
"sh -c \"npx --yes --loglevel=error supabase@latest {}\"",
"sh -c \"{} {}\"",
self.cli_source,
escape_for_sh_double_quotes(command)
);

Expand All @@ -137,7 +157,7 @@ Then re-run the command.",
pub async fn command_silent(self, command: &str) -> anyhow::Result<Output> {
self.validate().await?;

let full_command = format!("npx --yes --loglevel=error supabase@latest {}", command);
let full_command = format!("{} {}", self.cli_source, command);

Ok(Command::new("sh")
.stdin(Stdio::null())
Expand Down
17 changes: 14 additions & 3 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use crate::abstraction::CliSource;

#[allow(dead_code)]
pub static CONFIG_FILENAME: &str = "sbp.toml";

#[allow(dead_code)]
#[derive(Deserialize, Debug)]
pub(crate) struct Config {}
#[derive(Deserialize, Serialize, Debug)]
pub(crate) struct Config {
pub cli_source: CliSource
}

impl Default for Config{
fn default() -> Self {
Self{
cli_source: CliSource::Npx
}
}
}
36 changes: 31 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,44 @@ mod errors;
mod patched;
mod sys;

use std::path::PathBuf;
use crate::cli::Cli;
use crate::config::{CONFIG_FILENAME, Config};
use clap::Parser;
use figment::Figment;
use figment::providers::{Format, Toml};
use figment::providers::{Serialized, Toml, Format, Env};
use homedir::my_home;
use lazy_static::lazy_static;

lazy_static! {
static ref CONFIG: Option<Config> = Figment::new()
.merge(Toml::file(CONFIG_FILENAME))
.extract()
.ok();
static ref CONFIG: Config = {
let mut figment = Figment::new()
.merge(Serialized::defaults(Config::default()));

let env_fig = Figment::new().merge(Env::prefixed("SBP_"));
let env_cli_source: Option<String> = env_fig.extract_inner("cli_source").ok();
if let Some(cli_source) = env_cli_source {
match cli_source.as_str() {
"Npx" => {
figment = figment.merge(Serialized::defaults(Config{cli_source: abstraction::CliSource::Npx}));
}
"FromPath" => {
let env_cli_path: Option<PathBuf> = env_fig.extract_inner("cli_path").ok();
if let Some(path) = env_cli_path {
figment = figment.merge(Serialized::defaults(Config{cli_source: abstraction::CliSource::FromPath(path)}));
}
}
_ => { /* do nothing, not found env variables or value out of range */ }
}
}

if let Ok(Some(home)) = my_home() {
figment = figment.merge(Toml::file(&home.join(CONFIG_FILENAME)));
}

figment = figment.merge(Toml::file(CONFIG_FILENAME));
figment.extract().expect("Config Loading Failed")
};
}

#[tokio::main]
Expand Down