Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 'clean' subcommand #530

Merged
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: 2 additions & 0 deletions cargo-shuttle/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ pub enum Command {
/// Follow log output
follow: bool,
},
/// remove artifacts that were generated by cargo
Clean,
/// delete this shuttle service
Delete,
/// manage secrets for this shuttle service
Expand Down
10 changes: 10 additions & 0 deletions cargo-shuttle/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,16 @@ impl Client {
.await
}

pub async fn clean_project(&self, project: &ProjectName) -> Result<Vec<String>> {
let path = format!("/projects/{}/clean", project.as_str(),);

self.post(path, Option::<String>::None)
.await
.context("failed to get clean output")?
.to_json()
.await
}

pub async fn get_project(&self, project: &ProjectName) -> Result<project::Response> {
let path = format!("/projects/{}", project.as_str());

Expand Down
14 changes: 14 additions & 0 deletions cargo-shuttle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ impl Shuttle {
| Command::Deployment(..)
| Command::Project(..)
| Command::Delete
| Command::Clean
| Command::Secrets
| Command::Status
| Command::Logs { .. }
Expand Down Expand Up @@ -91,6 +92,7 @@ impl Shuttle {
self.deployment_get(&client, id).await
}
Command::Delete => self.delete(&client).await,
Command::Clean => self.clean(&client).await,
Command::Secrets => self.secrets(&client).await,
Command::Auth(auth_args) => self.auth(auth_args, &client).await,
Command::Project(ProjectCommand::New) => self.project_create(&client).await,
Expand Down Expand Up @@ -299,6 +301,18 @@ impl Shuttle {
Ok(())
}

async fn clean(&self, client: &Client) -> Result<()> {
let lines = client.clean_project(self.ctx.project_name()).await?;

for line in lines {
chesedo marked this conversation as resolved.
Show resolved Hide resolved
println!("{line}");
}

println!("Cleaning done!");

Ok(())
}

async fn logs(&self, client: &Client, id: Option<Uuid>, follow: bool) -> Result<()> {
let id = if let Some(id) = id {
id
Expand Down
9 changes: 8 additions & 1 deletion deployer/src/deployment/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const KILL_BUFFER_SIZE: usize = 10;
pub struct DeploymentManager {
pipeline: Pipeline,
kill_send: KillSender,
storage_manager: StorageManager,
}

impl DeploymentManager {
Expand All @@ -40,6 +41,7 @@ impl DeploymentManager {
artifacts_path: PathBuf,
) -> Self {
let (kill_send, _) = broadcast::channel(KILL_BUFFER_SIZE);
let storage_manager = StorageManager::new(artifacts_path);

DeploymentManager {
pipeline: Pipeline::new(
Expand All @@ -49,9 +51,10 @@ impl DeploymentManager {
build_log_recorder,
secret_recorder,
active_deployment_getter,
StorageManager::new(artifacts_path),
storage_manager.clone(),
),
kill_send,
storage_manager,
}
}

Expand All @@ -76,6 +79,10 @@ impl DeploymentManager {
self.kill_send.send(id).unwrap();
}
}

pub fn storage_manager(&self) -> StorageManager {
self.storage_manager.clone()
}
}

/// ```no-test
Expand Down
2 changes: 2 additions & 0 deletions deployer/src/handlers/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ pub enum Error {
},
#[error("record could not be found")]
NotFound,
#[error("Custom error: {0}")]
Custom(#[from] anyhow::Error),
}

impl Serialize for Error {
Expand Down
18 changes: 17 additions & 1 deletion deployer/src/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use axum::extract::ws::{self, WebSocket};
use axum::extract::{Extension, MatchedPath, Path, Query};
use axum::http::{Request, Response};
use axum::middleware::from_extractor;
use axum::routing::{get, Router};
use axum::routing::{get, post, Router};
use axum::{extract::BodyStream, Json};
use bytes::BufMut;
use chrono::{TimeZone, Utc};
Expand All @@ -17,6 +17,7 @@ use shuttle_common::backends::metrics::Metrics;
use shuttle_common::models::secret;
use shuttle_common::project::ProjectName;
use shuttle_common::LogItem;
use shuttle_service::loader::clean_crate;
use tower_http::auth::RequireAuthorizationLayer;
use tower_http::trace::TraceLayer;
use tracing::{debug, debug_span, error, field, trace, Span};
Expand Down Expand Up @@ -66,6 +67,7 @@ pub fn make_router(
"/projects/:project_name/secrets/:service_name",
get(get_secrets),
)
.route("/projects/:project_name/clean", post(post_clean))
.layer(Extension(persistence))
.layer(Extension(deployment_manager))
.layer(Extension(proxy_fqdn))
Expand Down Expand Up @@ -407,6 +409,20 @@ async fn get_secrets(
}
}

async fn post_clean(
Extension(deployment_manager): Extension<DeploymentManager>,
Path(project_name): Path<String>,
) -> Result<Json<Vec<String>>> {
let project_path = deployment_manager
.storage_manager()
.service_build_path(project_name)
.map_err(anyhow::Error::new)?;

let lines = clean_crate(&project_path, true)?;

Ok(Json(lines))
}

async fn get_status() -> String {
"Ok".to_string()
}
47 changes: 46 additions & 1 deletion service/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::path::{Path, PathBuf};
use anyhow::{anyhow, Context};
use cargo::core::compiler::{CompileMode, MessageFormat};
use cargo::core::{Manifest, PackageId, Shell, Summary, Verbosity, Workspace};
use cargo::ops::{compile, CompileOptions};
use cargo::ops::{clean, compile, CleanOptions, CompileOptions};
use cargo::util::interning::InternedString;
use cargo::util::{homedir, ToSemver};
use cargo::Config;
Expand Down Expand Up @@ -147,6 +147,51 @@ pub async fn build_crate(
Ok(compilation?.cdylibs[0].path.clone())
}

pub fn clean_crate(project_path: &Path, release_mode: bool) -> anyhow::Result<Vec<String>> {
let (read, write) = pipe::pipe();
let project_path = project_path.to_owned();

tokio::task::spawn_blocking(move || {
let config = get_config(write).unwrap();
let manifest_path = project_path.join("Cargo.toml");
let ws = Workspace::new(&manifest_path, &config).unwrap();

let requested_profile = if release_mode {
InternedString::new("release")
} else {
InternedString::new("dev")
};

let opts = CleanOptions {
config: &config,
spec: Vec::new(),
targets: Vec::new(),
requested_profile,
profile_specified: true,
doc: false,
};

clean(&ws, &opts).unwrap();
});

let mut lines = Vec::new();

for message in Message::parse_stream(read) {
chesedo marked this conversation as resolved.
Show resolved Hide resolved
trace!(?message, "parsed cargo message");
match message {
Ok(Message::TextLine(line)) => {
lines.push(line);
}
Ok(_) => {}
Err(error) => {
error!("failed to parse cargo message: {error}");
}
}
}

Ok(lines)
}

/// Get the default compile config with output redirected to writer
pub fn get_config(writer: PipeWriter) -> anyhow::Result<Config> {
let mut shell = Shell::from_write(Box::new(writer));
Expand Down