Skip to content

Commit

Permalink
refactor: getting project name (#774)
Browse files Browse the repository at this point in the history
* refactor: getting project name

* refactor: clippy suggestion

* Update cargo-shuttle/src/args.rs

Co-authored-by: Oddbjørn Grødem <29732646+oddgrd@users.noreply.github.com>

* refactor: rather use dunce

---------

Co-authored-by: Oddbjørn Grødem <29732646+oddgrd@users.noreply.github.com>
  • Loading branch information
chesedo and oddgrd authored Mar 31, 2023
1 parent ba241c5 commit 70457b0
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 55 deletions.
80 changes: 80 additions & 0 deletions cargo-shuttle/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use std::{
path::PathBuf,
};

use anyhow::Context;
use cargo_metadata::MetadataCommand;
use clap::builder::{OsStringValueParser, PossibleValue, TypedValueParser};
use clap::Parser;
use clap_complete::Shell;
Expand Down Expand Up @@ -46,6 +48,41 @@ pub struct ProjectArgs {
pub name: Option<ProjectName>,
}

impl ProjectArgs {
pub fn workspace_path(&self) -> anyhow::Result<PathBuf> {
let path = MetadataCommand::new()
.current_dir(&self.working_directory)
.exec()
.context("failed to get cargo metadata")?
.workspace_root
.into();

Ok(path)
}

pub fn project_name(&self) -> anyhow::Result<ProjectName> {
let workspace_path = self.workspace_path()?;

let meta = MetadataCommand::new()
.current_dir(&workspace_path)
.exec()
.unwrap();
let package_name = if let Some(root_package) = meta.root_package() {
root_package.name.clone().parse()?
} else {
workspace_path
.file_name()
.context("failed to get project name from workspace path")?
.to_os_string()
.into_string()
.expect("workspace file name should be valid unicode")
.parse()?
};

Ok(package_name)
}
}

#[derive(Parser)]
pub enum Command {
/// deploy a shuttle service
Expand Down Expand Up @@ -270,6 +307,8 @@ pub(crate) fn parse_init_path(path: OsString) -> Result<PathBuf, io::Error> {
mod tests {
use strum::IntoEnumIterator;

use crate::tests::path_from_workspace_root;

use super::*;

fn init_args_factory(framework: &str) -> InitArgs {
Expand Down Expand Up @@ -317,4 +356,45 @@ mod tests {
assert_eq!(args.framework(), Some(framework));
}
}

#[test]
fn workspace_path() {
let project_args = ProjectArgs {
working_directory: path_from_workspace_root("examples/axum/hello-world/src"),
name: None,
};

assert_eq!(
project_args.workspace_path().unwrap(),
path_from_workspace_root("examples/axum/hello-world/")
);
}

#[test]
fn project_name() {
let project_args = ProjectArgs {
working_directory: path_from_workspace_root("examples/axum/hello-world/src"),
name: None,
};

assert_eq!(
project_args.project_name().unwrap().to_string(),
"hello-world"
);
}

#[test]
fn project_name_in_workspace() {
let project_args = ProjectArgs {
working_directory: path_from_workspace_root(
"examples/rocket/workspace/hello-world/src",
),
name: None,
};

assert_eq!(
project_args.project_name().unwrap().to_string(),
"workspace"
);
}
}
41 changes: 19 additions & 22 deletions cargo-shuttle/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use std::io::{Read, Write};
use std::path::{Path, PathBuf};

use anyhow::{anyhow, Context, Result};
use cargo_metadata::MetadataCommand;
use serde::{Deserialize, Serialize};
use shuttle_common::project::ProjectName;
use shuttle_common::{ApiKey, ApiUrl, API_URL_DEFAULT};
Expand Down Expand Up @@ -236,25 +235,6 @@ pub struct RequestContext {
api_url: Option<String>,
}

fn find_crate_name<P: AsRef<Path>>(working_directory: P) -> Result<ProjectName> {
let meta = MetadataCommand::new()
.current_dir(working_directory.as_ref())
.exec()
.unwrap();
let package_name = meta
.root_package()
.ok_or_else(|| {
anyhow!(
"could not find a root package in `{}`",
working_directory.as_ref().display()
)
})?
.name
.clone()
.parse()?;
Ok(package_name)
}

impl RequestContext {
/// Create a [`RequestContext`], only loading in the global configuration details.
pub fn load_global() -> Result<Self> {
Expand Down Expand Up @@ -290,7 +270,7 @@ impl RequestContext {
project_args: &ProjectArgs,
) -> Result<Config<LocalConfigManager, ProjectConfig>> {
let local_manager =
LocalConfigManager::new(&project_args.working_directory, "Shuttle.toml".to_string());
LocalConfigManager::new(project_args.workspace_path()?, "Shuttle.toml".to_string());
let mut project = Config::new(local_manager);

if !project.exists() {
Expand All @@ -302,6 +282,11 @@ impl RequestContext {

let config = project.as_mut().unwrap();

// Project names are preferred in this order:
// 1. Name given on command line
// 2. Name from Shuttle.toml file
// 3. Name from Cargo.toml package if it's a crate
// 3. Name from the workspace directory if it's a workspace
match (&project_args.name, &config.name) {
// Command-line name parameter trumps everything
(Some(name_from_args), _) => {
Expand All @@ -315,7 +300,7 @@ impl RequestContext {
// If name key is not in project config, then we infer from crate name
(None, None) => {
trace!("using crate name as project name");
config.name = Some(find_crate_name(&project_args.working_directory)?);
config.name = Some(project_args.project_name()?);
}
};
Ok(project)
Expand Down Expand Up @@ -432,6 +417,18 @@ mod tests {
assert_eq!(unwrap_project_name(&local_config), "hello-world-axum-app");
}

#[test]
fn get_local_config_finds_name_from_workspace_dir() {
let project_args = ProjectArgs {
working_directory: path_from_workspace_root("examples/rocket/workspace/hello-world/"),
name: None,
};

let local_config = RequestContext::get_local_config(&project_args).unwrap();

assert_eq!(unwrap_project_name(&local_config), "workspace");
}

#[test]
fn setting_name_overrides_name_in_config() {
let project_args = ProjectArgs {
Expand Down
78 changes: 45 additions & 33 deletions cargo-shuttle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,21 +231,8 @@ impl Shuttle {
Ok(())
}

fn find_root_directory(dir: &Path) -> Option<PathBuf> {
dir.ancestors()
.find(|ancestor| ancestor.join("Cargo.toml").exists())
.map(|path| path.to_path_buf())
}

pub fn load_project(&mut self, project_args: &mut ProjectArgs) -> Result<()> {
trace!("loading project arguments: {project_args:?}");
let root_directory_path = Self::find_root_directory(&project_args.working_directory);

if let Some(working_directory) = root_directory_path {
project_args.working_directory = working_directory;
} else {
return Err(anyhow!("Could not locate the root of a cargo project. Are you inside a cargo project? You can also use `--working-directory` to locate your cargo project."));
}

self.ctx.load_local(project_args)
}
Expand Down Expand Up @@ -1004,10 +991,12 @@ mod tests {
use std::path::PathBuf;
use std::str::FromStr;

fn path_from_workspace_root(path: &str) -> PathBuf {
PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap())
pub fn path_from_workspace_root(path: &str) -> PathBuf {
let path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap())
.join("..")
.join(path)
.join(path);

dunce::canonicalize(path).unwrap()
}

fn get_archive_entries(mut project_args: ProjectArgs) -> Vec<String> {
Expand Down Expand Up @@ -1037,18 +1026,6 @@ mod tests {
.collect()
}

#[test]
fn find_root_directory_returns_proper_directory() {
let working_directory = path_from_workspace_root("examples/axum/hello-world/src");

let root_dir = Shuttle::find_root_directory(&working_directory).unwrap();

assert_eq!(
root_dir,
path_from_workspace_root("examples/axum/hello-world/")
);
}

#[test]
fn load_project_returns_proper_working_directory_in_project_args() {
let mut project_args = ProjectArgs {
Expand All @@ -1061,7 +1038,11 @@ mod tests {

assert_eq!(
project_args.working_directory,
path_from_workspace_root("examples/axum/hello-world/")
path_from_workspace_root("examples/axum/hello-world/src")
);
assert_eq!(
project_args.workspace_path().unwrap(),
path_from_workspace_root("examples/axum/hello-world")
);
}

Expand Down Expand Up @@ -1105,7 +1086,21 @@ mod tests {

fs::write(working_directory.join(".env"), "API_KEY = 'blabla'").unwrap();
fs::write(working_directory.join(".ignore"), ".env").unwrap();
fs::write(working_directory.join("Cargo.toml"), "[package]").unwrap();
fs::write(
working_directory.join("Cargo.toml"),
r#"
[package]
name = "secrets"
version = "0.1.0"
"#,
)
.unwrap();
fs::create_dir_all(working_directory.join("src")).unwrap();
fs::write(
working_directory.join("src").join("main.rs"),
"fn main() {}",
)
.unwrap();

let project_args = ProjectArgs {
working_directory: working_directory.to_path_buf(),
Expand All @@ -1115,7 +1110,10 @@ mod tests {
let mut entries = get_archive_entries(project_args);
entries.sort();

assert_eq!(entries, vec![".ignore", "Cargo.toml"]);
assert_eq!(
entries,
vec![".ignore", "Cargo.lock", "Cargo.toml", "src/main.rs"]
);
}

#[test]
Expand All @@ -1125,7 +1123,21 @@ mod tests {

fs::create_dir_all(working_directory.join("target")).unwrap();
fs::write(working_directory.join("target").join("binary"), "12345").unwrap();
fs::write(working_directory.join("Cargo.toml"), "[package]").unwrap();
fs::write(
working_directory.join("Cargo.toml"),
r#"
[package]
name = "exclude_target"
version = "0.1.0"
"#,
)
.unwrap();
fs::create_dir_all(working_directory.join("src")).unwrap();
fs::write(
working_directory.join("src").join("main.rs"),
"fn main() {}",
)
.unwrap();

let project_args = ProjectArgs {
working_directory: working_directory.to_path_buf(),
Expand All @@ -1135,6 +1147,6 @@ mod tests {
let mut entries = get_archive_entries(project_args);
entries.sort();

assert_eq!(entries, vec!["Cargo.toml"]);
assert_eq!(entries, vec!["Cargo.lock", "Cargo.toml", "src/main.rs"]);
}
}

0 comments on commit 70457b0

Please sign in to comment.