From fe5465a265a03609e4ef3211e523361f70b1c20a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 22 Dec 2021 08:19:19 -0700 Subject: [PATCH 1/7] Enable authentication via the NextJS site --- crates/client/src/client.rs | 41 +++++++++++++++--------------- crates/server/src/api.rs | 50 +++++++++++++++++++++++++++++++++---- crates/server/src/auth.rs | 19 +++++++++----- 3 files changed, 79 insertions(+), 31 deletions(-) diff --git a/crates/client/src/client.rs b/crates/client/src/client.rs index 652278d785116484bc5275e22427b87652963c32..000f47507c87febcc88ef52c7fe974a23bedb6a7 100644 --- a/crates/client/src/client.rs +++ b/crates/client/src/client.rs @@ -35,8 +35,10 @@ pub use rpc::*; pub use user::*; lazy_static! { - static ref ZED_SERVER_URL: String = - std::env::var("ZED_SERVER_URL").unwrap_or("https://zed.dev:443".to_string()); + static ref COLLAB_URL: String = + std::env::var("ZED_COLLAB_URL").unwrap_or("https://collab.zed.dev:443".to_string()); + static ref SITE_URL: String = + std::env::var("ZED_SITE_URL").unwrap_or("https://zed.dev".to_string()); static ref IMPERSONATE_LOGIN: Option = std::env::var("ZED_IMPERSONATE") .ok() .and_then(|s| if s.is_empty() { None } else { Some(s) }); @@ -403,7 +405,7 @@ impl Client { match self.establish_connection(&credentials, cx).await { Ok(conn) => { - log::info!("connected to rpc address {}", *ZED_SERVER_URL); + log::info!("connected to rpc address {}", *COLLAB_URL); self.state.write().credentials = Some(credentials.clone()); if !used_keychain && IMPERSONATE_LOGIN.is_none() { write_credentials_to_keychain(&credentials, cx).log_err(); @@ -414,7 +416,7 @@ impl Client { Err(EstablishConnectionError::Unauthorized) => { self.state.write().credentials.take(); if used_keychain { - cx.platform().delete_credentials(&ZED_SERVER_URL).log_err(); + cx.platform().delete_credentials(&COLLAB_URL).log_err(); self.set_status(Status::SignedOut, cx); self.authenticate_and_connect(cx).await } else { @@ -522,19 +524,19 @@ impl Client { ) .header("X-Zed-Protocol-Version", rpc::PROTOCOL_VERSION); cx.background().spawn(async move { - if let Some(host) = ZED_SERVER_URL.strip_prefix("https://") { + if let Some(host) = COLLAB_URL.strip_prefix("https://") { let stream = smol::net::TcpStream::connect(host).await?; let request = request.uri(format!("wss://{}/rpc", host)).body(())?; let (stream, _) = async_tungstenite::async_tls::client_async_tls(request, stream).await?; Ok(Connection::new(stream)) - } else if let Some(host) = ZED_SERVER_URL.strip_prefix("http://") { + } else if let Some(host) = COLLAB_URL.strip_prefix("http://") { let stream = smol::net::TcpStream::connect(host).await?; let request = request.uri(format!("ws://{}/rpc", host)).body(())?; let (stream, _) = async_tungstenite::client_async(request, stream).await?; Ok(Connection::new(stream)) } else { - Err(anyhow!("invalid server url: {}", *ZED_SERVER_URL))? + Err(anyhow!("invalid server url: {}", *COLLAB_URL))? } }) } @@ -561,8 +563,8 @@ impl Client { // Open the Zed sign-in page in the user's browser, with query parameters that indicate // that the user is signing in from a Zed app running on the same device. let mut url = format!( - "{}/sign_in?native_app_port={}&native_app_public_key={}", - *ZED_SERVER_URL, port, public_key_string + "{}/native_app_signin?native_app_port={}&native_app_public_key={}", + *SITE_URL, port, public_key_string ); if let Some(impersonate_login) = IMPERSONATE_LOGIN.as_ref() { @@ -592,9 +594,15 @@ impl Client { user_id = Some(value.to_string()); } } + + let post_auth_url = format!("{}/native_app_signin_succeeded", *SITE_URL); req.respond( - tiny_http::Response::from_string(LOGIN_RESPONSE).with_header( - tiny_http::Header::from_bytes("Content-Type", "text/html").unwrap(), + tiny_http::Response::empty(302).with_header( + tiny_http::Header::from_bytes( + &b"Location"[..], + post_auth_url.as_bytes(), + ) + .unwrap(), ), ) .context("failed to respond to login http request")?; @@ -660,7 +668,7 @@ fn read_credentials_from_keychain(cx: &AsyncAppContext) -> Option { let (user_id, access_token) = cx .platform() - .read_credentials(&ZED_SERVER_URL) + .read_credentials(&COLLAB_URL) .log_err() .flatten()?; Some(Credentials { @@ -671,7 +679,7 @@ fn read_credentials_from_keychain(cx: &AsyncAppContext) -> Option { fn write_credentials_to_keychain(credentials: &Credentials, cx: &AsyncAppContext) -> Result<()> { cx.platform().write_credentials( - &ZED_SERVER_URL, + &COLLAB_URL, &credentials.user_id.to_string(), credentials.access_token.as_bytes(), ) @@ -694,13 +702,6 @@ pub fn decode_worktree_url(url: &str) -> Option<(u64, String)> { Some((id, access_token.to_string())) } -const LOGIN_RESPONSE: &'static str = " - - - - -"; - #[cfg(test)] mod tests { use super::*; diff --git a/crates/server/src/api.rs b/crates/server/src/api.rs index 4ff31bb13ddd4153d25ed28463308db6e0b72e8e..9f8e62d51f3de6ef7c9c7692514557e0413cfadb 100644 --- a/crates/server/src/api.rs +++ b/crates/server/src/api.rs @@ -1,7 +1,9 @@ use crate::{auth, AppState, Request, RequestExt as _}; use async_trait::async_trait; +use serde::Deserialize; use serde_json::json; use std::sync::Arc; +use surf::StatusCode; pub fn add_routes(app: &mut tide::Server>) { app.at("/users/:github_login").get(get_user); @@ -18,7 +20,7 @@ async fn get_user(request: Request) -> tide::Result { .await? .ok_or_else(|| surf::Error::from_str(404, "user not found"))?; - Ok(tide::Response::builder(200) + Ok(tide::Response::builder(StatusCode::Ok) .body(tide::Body::from_json(&user)?) .build()) } @@ -30,11 +32,49 @@ async fn create_access_token(request: Request) -> tide::Result { .db() .get_user_by_github_login(request.param("github_login")?) .await? - .ok_or_else(|| surf::Error::from_str(404, "user not found"))?; - let token = auth::create_access_token(request.db(), user.id).await?; + .ok_or_else(|| surf::Error::from_str(StatusCode::NotFound, "user not found"))?; + let access_token = auth::create_access_token(request.db(), user.id).await?; + + #[derive(Deserialize)] + struct QueryParams { + public_key: String, + impersonate: Option, + } + + let query_params: QueryParams = request.query().map_err(|_| { + surf::Error::from_str(StatusCode::UnprocessableEntity, "invalid query params") + })?; + + let encrypted_access_token = + auth::encrypt_access_token(&access_token, query_params.public_key.clone())?; + + let mut user_id = user.id; + if let Some(impersonate) = query_params.impersonate { + if user.admin { + if let Some(impersonated_user) = + request.db().get_user_by_github_login(&impersonate).await? + { + user_id = impersonated_user.id; + } else { + return Ok(tide::Response::builder(StatusCode::UnprocessableEntity) + .body(format!( + "Can't impersonate non-existent user {}", + impersonate + )) + .build()); + } + } else { + return Ok(tide::Response::builder(StatusCode::Unauthorized) + .body(format!( + "Can't impersonate user {} because the real user isn't an admin", + impersonate + )) + .build()); + } + } - Ok(tide::Response::builder(200) - .body(json!({"user_id": user.id, "access_token": token})) + Ok(tide::Response::builder(StatusCode::Ok) + .body(json!({"user_id": user_id, "encrypted_access_token": encrypted_access_token})) .build()) } diff --git a/crates/server/src/auth.rs b/crates/server/src/auth.rs index 9c6142618fc787b59c407a3c35cf402789a40ec4..9b2c355226c71f154a7b03d1de1af8560d081b3b 100644 --- a/crates/server/src/auth.rs +++ b/crates/server/src/auth.rs @@ -238,12 +238,10 @@ async fn get_auth_callback(mut request: Request) -> tide::Result { } let access_token = create_access_token(request.db(), user_id).await?; - let native_app_public_key = - zed_auth::PublicKey::try_from(app_sign_in_params.native_app_public_key.clone()) - .context("failed to parse app public key")?; - let encrypted_access_token = native_app_public_key - .encrypt_string(&access_token) - .context("failed to encrypt access token with public key")?; + let encrypted_access_token = encrypt_access_token( + &access_token, + app_sign_in_params.native_app_public_key.clone(), + )?; return Ok(tide::Redirect::new(&format!( "http://127.0.0.1:{}?user_id={}&access_token={}", @@ -289,6 +287,15 @@ fn hash_access_token(token: &str) -> tide::Result { .to_string()) } +pub fn encrypt_access_token(access_token: &str, public_key: String) -> tide::Result { + let native_app_public_key = + zed_auth::PublicKey::try_from(public_key).context("failed to parse app public key")?; + let encrypted_access_token = native_app_public_key + .encrypt_string(&access_token) + .context("failed to encrypt access token with public key")?; + Ok(encrypted_access_token) +} + pub fn verify_access_token(token: &str, hash: &str) -> tide::Result { let hash = PasswordHash::new(hash)?; Ok(Scrypt.verify_password(token.as_bytes(), &hash).is_ok()) From 07a4cfeefde2d8e27ae6527d0a00892ba987c29d Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 22 Dec 2021 08:38:17 -0700 Subject: [PATCH 2/7] Streamline running both next and collab servers in development Co-Authored-By: Antonio Scandurra --- Procfile | 2 ++ README.md | 34 +++++++++++++++++++++++++++++----- script/server | 6 ------ script/zed_with_local_servers | 1 + 4 files changed, 32 insertions(+), 11 deletions(-) create mode 100644 Procfile delete mode 100755 script/server create mode 100755 script/zed_with_local_servers diff --git a/Procfile b/Procfile new file mode 100644 index 0000000000000000000000000000000000000000..c859a2d46b32c4fe2e532fae9fa63916bf04deb5 --- /dev/null +++ b/Procfile @@ -0,0 +1,2 @@ +collab: cd crates/server && cargo run +site: cd ../zed.dev && PORT=3000 npx next dev diff --git a/README.md b/README.md index eaa9ea50abc63a2e40a9423de50df21953943d36..92ce2bb758ae7375b95e9eee74d90674f2d471f0 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,30 @@ The Zed server uses libcurl, which currently triggers [a bug](https://github.com export MACOSX_DEPLOYMENT_TARGET=10.7 ``` +### Testing against locally-running servers + +Make sure you have `zed.dev` cloned as a sibling to this repo. + +``` +cd .. +git clone https://github.com/zed-industries/zed.dev +``` + +Run `zed.dev` and the collaboration server. + +``` +brew install foreman +foreman start +``` + +If you want to run Zed pointed at the local servers, you can run: + +``` +script/zed_with_local_servers +# or... +script/zed_with_local_servers --release +``` + ### Dump element JSON If you trigger `cmd-shift-i`, Zed will copy a JSON representation of the current window contents to the clipboard. You can paste this in a tool like [DJSON](https://chrome.google.com/webstore/detail/djson-json-viewer-formatt/chaeijjekipecdajnijdldjjipaegdjc?hl=en) to navigate the state of on-screen elements in a structured way. @@ -34,12 +58,12 @@ Establish basic infrastructure for building the app bundle and uploading an arti [Tracking issue](https://github.com/zed-industries/zed/issues/6) -Turn the minimal text editor into a collaborative *code* editor. This will include the minimal features that the Zed team needs to collaborate in Zed to build Zed without net loss in developer productivity. This includes productivity-critical features such as: +Turn the minimal text editor into a collaborative _code_ editor. This will include the minimal features that the Zed team needs to collaborate in Zed to build Zed without net loss in developer productivity. This includes productivity-critical features such as: -* Syntax highlighting and syntax-aware editing and navigation -* The ability to see and edit non-local working copies of a repository -* Language server support for Rust code navigation, refactoring, diagnostics, etc. -* Project browsing and project-wide search and replace +- Syntax highlighting and syntax-aware editing and navigation +- The ability to see and edit non-local working copies of a repository +- Language server support for Rust code navigation, refactoring, diagnostics, etc. +- Project browsing and project-wide search and replace We want to tackle collaboration fairly early so that the rest of the design of the product can flow around that assumption. We could probably produce a single-player code editor more quickly, but at the risk of having collaboration feel more "bolted on" when we eventually add it. diff --git a/script/server b/script/server deleted file mode 100755 index f85ab348e156b8e567b079ab07657457aedf2f59..0000000000000000000000000000000000000000 --- a/script/server +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -set -e - -cd crates/server -cargo run $@ diff --git a/script/zed_with_local_servers b/script/zed_with_local_servers new file mode 100755 index 0000000000000000000000000000000000000000..18ccdf3141909315c13775e88ce954f9c662029e --- /dev/null +++ b/script/zed_with_local_servers @@ -0,0 +1 @@ +ZED_SITE_URL=http://localhost:3000 ZED_COLLAB_URL=http://localhost:8080 cargo run $@ From 56930972feb2f3891eb6bd5c025476593c1f1235 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 23 Dec 2021 18:20:24 -0700 Subject: [PATCH 3/7] Add endpoints for listing, creating, and updating users --- crates/server/src/api.rs | 65 +++++++++++++++++++++++++++++++++++++++- crates/server/src/db.rs | 5 ++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/crates/server/src/api.rs b/crates/server/src/api.rs index 9f8e62d51f3de6ef7c9c7692514557e0413cfadb..9510c2fc103d0e23d2bfa8c149da561595dd9a96 100644 --- a/crates/server/src/api.rs +++ b/crates/server/src/api.rs @@ -1,4 +1,4 @@ -use crate::{auth, AppState, Request, RequestExt as _}; +use crate::{auth, db::UserId, AppState, Request, RequestExt as _}; use async_trait::async_trait; use serde::Deserialize; use serde_json::json; @@ -6,6 +6,9 @@ use std::sync::Arc; use surf::StatusCode; pub fn add_routes(app: &mut tide::Server>) { + app.at("/users").get(get_users); + app.at("/users").post(create_user); + app.at("/users/:id").put(update_user); app.at("/users/:github_login").get(get_user); app.at("/users/:github_login/access_tokens") .post(create_access_token); @@ -25,6 +28,66 @@ async fn get_user(request: Request) -> tide::Result { .build()) } +async fn get_users(request: Request) -> tide::Result { + request.require_token().await?; + + let users = request.db().get_all_users().await?; + + Ok(tide::Response::builder(StatusCode::Ok) + .body(tide::Body::from_json(&users)?) + .build()) +} + +async fn create_user(mut request: Request) -> tide::Result { + request.require_token().await?; + + #[derive(Deserialize)] + struct Params { + github_login: String, + admin: bool, + } + let params = request.body_json::().await?; + + let user_id = request + .db() + .create_user(¶ms.github_login, params.admin) + .await?; + + let user = request.db().get_user_by_id(user_id).await?.ok_or_else(|| { + surf::Error::from_str( + StatusCode::InternalServerError, + "couldn't find the user we just created", + ) + })?; + + Ok(tide::Response::builder(StatusCode::Ok) + .body(tide::Body::from_json(&user)?) + .build()) +} + +async fn update_user(mut request: Request) -> tide::Result { + request.require_token().await?; + + #[derive(Deserialize)] + struct Params { + admin: bool, + } + let user_id = UserId( + request + .param("id")? + .parse::() + .map_err(|error| surf::Error::from_str(StatusCode::BadRequest, error.to_string()))?, + ); + let params = request.body_json::().await?; + + request + .db() + .set_user_is_admin(user_id, params.admin) + .await?; + + Ok(tide::Response::builder(StatusCode::Ok).build()) +} + async fn create_access_token(request: Request) -> tide::Result { request.require_token().await?; diff --git a/crates/server/src/db.rs b/crates/server/src/db.rs index e3267bad0e7aa7ac1f725649d82e7d4d7ee72bf2..e8a1023a92ede73800f4db3552d185e40a595400 100644 --- a/crates/server/src/db.rs +++ b/crates/server/src/db.rs @@ -121,6 +121,11 @@ impl Db { }) } + pub async fn get_user_by_id(&self, id: UserId) -> Result> { + let users = self.get_users_by_ids([id]).await?; + Ok(users.into_iter().next()) + } + pub async fn get_users_by_ids( &self, ids: impl IntoIterator, From b949b30f24b9f4f08387f292a9ffd69f87709b36 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 25 Dec 2021 11:57:37 -0700 Subject: [PATCH 4/7] Add delete user endpoint --- crates/server/src/api.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/crates/server/src/api.rs b/crates/server/src/api.rs index 9510c2fc103d0e23d2bfa8c149da561595dd9a96..a4e24083a3f63fdd47263920c03b813dae259c17 100644 --- a/crates/server/src/api.rs +++ b/crates/server/src/api.rs @@ -9,6 +9,7 @@ pub fn add_routes(app: &mut tide::Server>) { app.at("/users").get(get_users); app.at("/users").post(create_user); app.at("/users/:id").put(update_user); + app.at("/users/:id").delete(delete_user); app.at("/users/:github_login").get(get_user); app.at("/users/:github_login/access_tokens") .post(create_access_token); @@ -88,6 +89,20 @@ async fn update_user(mut request: Request) -> tide::Result { Ok(tide::Response::builder(StatusCode::Ok).build()) } +async fn delete_user(request: Request) -> tide::Result { + request.require_token().await?; + let user_id = UserId( + request + .param("id")? + .parse::() + .map_err(|error| surf::Error::from_str(StatusCode::BadRequest, error.to_string()))?, + ); + + request.db().delete_user(user_id).await?; + + Ok(tide::Response::builder(StatusCode::Ok).build()) +} + async fn create_access_token(request: Request) -> tide::Result { request.require_token().await?; From 63238a293898f5709067cfdcabd3ce1d00601754 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 25 Dec 2021 17:46:02 -0700 Subject: [PATCH 5/7] Destroy access tokens before destroying users and word-smith method names --- crates/server/src/admin.rs | 4 ++-- crates/server/src/api.rs | 6 +++--- crates/server/src/db.rs | 10 ++++++++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/crates/server/src/admin.rs b/crates/server/src/admin.rs index 90c74ca7a4f85ee14fe94c71aed11c6ef9a3b09e..62e518ee6e14db6e25fd0b06284126a638968ffb 100644 --- a/crates/server/src/admin.rs +++ b/crates/server/src/admin.rs @@ -105,13 +105,13 @@ async fn put_user(mut request: Request) -> tide::Result { async fn delete_user(request: Request) -> tide::Result { request.require_admin().await?; let user_id = db::UserId(request.param("id")?.parse()?); - request.db().delete_user(user_id).await?; + request.db().destroy_user(user_id).await?; Ok(tide::Redirect::new("/admin").into()) } async fn delete_signup(request: Request) -> tide::Result { request.require_admin().await?; let signup_id = db::SignupId(request.param("id")?.parse()?); - request.db().delete_signup(signup_id).await?; + request.db().destroy_signup(signup_id).await?; Ok(tide::Redirect::new("/admin").into()) } diff --git a/crates/server/src/api.rs b/crates/server/src/api.rs index a4e24083a3f63fdd47263920c03b813dae259c17..0999a28d9027d5829fdea6c9b4a64616dbca7a7a 100644 --- a/crates/server/src/api.rs +++ b/crates/server/src/api.rs @@ -9,7 +9,7 @@ pub fn add_routes(app: &mut tide::Server>) { app.at("/users").get(get_users); app.at("/users").post(create_user); app.at("/users/:id").put(update_user); - app.at("/users/:id").delete(delete_user); + app.at("/users/:id").delete(destroy_user); app.at("/users/:github_login").get(get_user); app.at("/users/:github_login/access_tokens") .post(create_access_token); @@ -89,7 +89,7 @@ async fn update_user(mut request: Request) -> tide::Result { Ok(tide::Response::builder(StatusCode::Ok).build()) } -async fn delete_user(request: Request) -> tide::Result { +async fn destroy_user(request: Request) -> tide::Result { request.require_token().await?; let user_id = UserId( request @@ -98,7 +98,7 @@ async fn delete_user(request: Request) -> tide::Result { .map_err(|error| surf::Error::from_str(StatusCode::BadRequest, error.to_string()))?, ); - request.db().delete_user(user_id).await?; + request.db().destroy_user(user_id).await?; Ok(tide::Response::builder(StatusCode::Ok).build()) } diff --git a/crates/server/src/db.rs b/crates/server/src/db.rs index e8a1023a92ede73800f4db3552d185e40a595400..f71f40efd08aae42b5f869b13bf8fbae77ee7cd6 100644 --- a/crates/server/src/db.rs +++ b/crates/server/src/db.rs @@ -84,7 +84,7 @@ impl Db { }) } - pub async fn delete_signup(&self, id: SignupId) -> Result<()> { + pub async fn destroy_signup(&self, id: SignupId) -> Result<()> { test_support!(self, { let query = "DELETE FROM signups WHERE id = $1"; sqlx::query(query) @@ -164,8 +164,14 @@ impl Db { }) } - pub async fn delete_user(&self, id: UserId) -> Result<()> { + pub async fn destroy_user(&self, id: UserId) -> Result<()> { test_support!(self, { + let query = "DELETE FROM access_tokens WHERE user_id = $1;"; + sqlx::query(query) + .bind(id.0) + .execute(&self.pool) + .await + .map(drop)?; let query = "DELETE FROM users WHERE id = $1;"; sqlx::query(query) .bind(id.0) From 8937d877e39cb9dbfd7d605558328ec3c7196b15 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 27 Dec 2021 12:22:59 -0800 Subject: [PATCH 6/7] :lipstick: --- Procfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Procfile b/Procfile index c859a2d46b32c4fe2e532fae9fa63916bf04deb5..08bff5acc2723aea8bc50fcb0071fe56126c512a 100644 --- a/Procfile +++ b/Procfile @@ -1,2 +1,2 @@ +web: cd ../zed.dev && PORT=3000 npx next dev collab: cd crates/server && cargo run -site: cd ../zed.dev && PORT=3000 npx next dev From 13ed9dc1f135a1d60160aecfe09393b32ae7d32f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 27 Dec 2021 12:52:15 -0800 Subject: [PATCH 7/7] Document database setup and fix issue in script/seed-db Co-Authored-By: Max Brunsfeld --- README.md | 8 ++++++++ crates/server/src/bin/seed.rs | 9 --------- script/seed-db | 7 ++++++- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 92ce2bb758ae7375b95e9eee74d90674f2d471f0..a70aa29637c8a9a7f6b8e68c5f07fedd7529ea33 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,14 @@ cd .. git clone https://github.com/zed-industries/zed.dev ``` +Make sure your local database is created, migrated, and seeded with initial data. Install [Postgres](https://postgresapp.com), then from the `zed` repository root, run: + +``` +script/sqlx database create +script/sqlx migrate run +script/seed-db +``` + Run `zed.dev` and the collaboration server. ``` diff --git a/crates/server/src/bin/seed.rs b/crates/server/src/bin/seed.rs index 4d3fb978dbd7db0a08c1c84fa816dece3d6f86ff..d5400d00088f75e1359e1059d3e47dc7d9f8ad22 100644 --- a/crates/server/src/bin/seed.rs +++ b/crates/server/src/bin/seed.rs @@ -6,18 +6,9 @@ use time::{Duration, OffsetDateTime}; #[allow(unused)] #[path = "../db.rs"] mod db; -#[path = "../env.rs"] -mod env; #[async_std::main] async fn main() { - if let Err(error) = env::load_dotenv() { - log::error!( - "error loading .env.toml (this is expected in production): {}", - error - ); - } - let mut rng = StdRng::from_entropy(); let database_url = std::env::var("DATABASE_URL").expect("missing DATABASE_URL env var"); let db = Db::new(&database_url, 5) diff --git a/script/seed-db b/script/seed-db index f42a33ba002411298a759608fabff52f12841616..437d1bcac89f6415ddd4dcfd96e4391d57ebde46 100755 --- a/script/seed-db +++ b/script/seed-db @@ -1,4 +1,9 @@ #!/bin/bash - set -e + +cd crates/server + +# Export contents of .env.toml +eval "$(cargo run --bin dotenv)" + cargo run --package=zed-server --features seed-support --bin seed