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

Update pyproject.toml if command packages aren't already listed #512

Merged
merged 2 commits into from
Mar 27, 2023
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
54 changes: 50 additions & 4 deletions src/huak/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,15 @@ impl Project {
self.pyproject_toml.dependencies()
}

/// Get a group of optional dependencies from the Python project's project file.
/// Get a group of optional dependencies from the Python project's manifest file.
pub fn optional_dependencey_group(
&self,
group_name: &str,
) -> Option<&Vec<String>> {
self.pyproject_toml.optional_dependencey_group(group_name)
}

/// Add a Python package as a dependency to the project's project file.
/// Add a Python package as a dependency to the project's manifest file.
pub fn add_dependency(&mut self, package_str: &str) {
self.pyproject_toml.add_dependency(package_str);
}
Expand All @@ -144,12 +144,12 @@ impl Project {
.add_optional_dependency(package_str, group_name)
}

/// Remove a dependency from the project's project file.
/// Remove a dependency from the project's manifest file.
pub fn remove_dependency(&mut self, package_str: &str) {
self.pyproject_toml.remove_dependency(package_str);
}

/// Remove an optional dependency from the project's project file.
/// Remove an optional dependency from the project's manifest file.
pub fn remove_optional_dependency(
&mut self,
package_str: &str,
Expand All @@ -158,6 +158,52 @@ impl Project {
self.pyproject_toml
.remove_optional_dependency(package_str, group_name);
}

/// Check if the project has a dependency listed in its manifest file.
pub fn has_dependency(&self, package_str: &str) -> HuakResult<bool> {
let package = Package::from_str(package_str)?;
let dependencies = match self.dependencies() {
Some(it) => it,
None => return Ok(false),
};
for dependency in dependencies {
if Package::from_str(dependency)?.name() == package.name() {
return Ok(true);
}
}
Ok(false)
}

/// Check if the project has an optional dependency listed in its manifest file.
pub fn has_optional_dependency(
&self,
package_str: &str,
) -> HuakResult<bool> {
let groups: Vec<&String> = match self.pyproject_toml.project.as_ref() {
Some(it) => match it.optional_dependencies.as_ref() {
Some(it) => it.keys().collect(),
None => Vec::new(),
},
None => return Ok(false),
};
if groups.is_empty() {
return Ok(false);
}
let package = Package::from_str(package_str)?;

for group in groups {
let dependencies = match self.optional_dependencey_group(group) {
Some(it) => it,
None => continue,
};
for dependency in dependencies {
if Package::from_str(dependency)?.name() == package.name() {
return Ok(true);
}
}
}
Ok(false)
}
}

impl From<ProjectType> for Project {
Expand Down
59 changes: 53 additions & 6 deletions src/huak/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub struct OperationConfig {
pub clean_options: Option<CleanOptions>,
}

/// Add Python packages as a dependencies to a Python project.
/// Add Python packages as dependencies to a Python project.
pub fn add_project_dependencies(
dependencies: &[&str],
config: &OperationConfig,
Expand Down Expand Up @@ -101,6 +101,8 @@ pub fn add_project_optional_dependencies(
/// Build the Python project as installable package.
pub fn build_project(config: &OperationConfig) -> HuakResult<()> {
let mut terminal = terminal_from_options(&config.terminal_options);
let manifest_path = config.workspace_root.join("pyproject.toml");
let mut project = Project::from_manifest(&manifest_path)?;
let venv = find_or_create_virtual_environment(config, &mut terminal)?;
if !venv.has_module("build")? {
venv.install_packages(
Expand All @@ -109,6 +111,12 @@ pub fn build_project(config: &OperationConfig) -> HuakResult<()> {
&mut terminal,
)?;
}
if !project.has_dependency("build")?
&& !project.has_optional_dependency("build")?
{
project.add_optional_dependency("build", "dev");
project.pyproject_toml().write_file(&manifest_path)?;
}
let mut cmd = Command::new(venv.python_path());
let mut args = vec!["-m", "build"];
if let Some(it) = config.build_options.as_ref() {
Expand Down Expand Up @@ -176,6 +184,8 @@ pub fn clean_project(config: &OperationConfig) -> HuakResult<()> {
/// Format the Python project's source code.
pub fn format_project(config: &OperationConfig) -> HuakResult<()> {
let mut terminal = terminal_from_options(&config.terminal_options);
let manifest_path = config.workspace_root.join("pyproject.toml");
let mut project = Project::from_manifest(&manifest_path)?;
let venv = find_or_create_virtual_environment(config, &mut terminal)?;
let packages: HuakResult<Vec<Package>> = ["black", "ruff"]
.iter()
Expand All @@ -190,6 +200,14 @@ pub fn format_project(config: &OperationConfig) -> HuakResult<()> {
&mut terminal,
)?;
}
for package in &packages {
if !project.has_dependency(package.name())?
&& !project.has_optional_dependency(package.name())?
{
project.add_optional_dependency(package.name(), "dev");
project.pyproject_toml().write_file(&manifest_path)?;
}
}
let mut cmd = Command::new(venv.python_path());
let mut ruff_cmd = Command::new(venv.python_path());
let mut ruff_args =
Expand Down Expand Up @@ -298,6 +316,8 @@ pub fn install_project_optional_dependencies(
/// Lint a Python project's source code.
pub fn lint_project(config: &OperationConfig) -> HuakResult<()> {
let mut terminal = terminal_from_options(&config.terminal_options);
let manifest_path = config.workspace_root.join("pyproject.toml");
let mut project = Project::from_manifest(&manifest_path)?;
let venv = find_or_create_virtual_environment(config, &mut terminal)?;
if !venv.has_module("ruff")? {
venv.install_packages(
Expand All @@ -306,6 +326,12 @@ pub fn lint_project(config: &OperationConfig) -> HuakResult<()> {
&mut terminal,
)?;
}
if !project.has_dependency("ruff")?
&& !project.has_optional_dependency("ruff")?
{
project.add_optional_dependency("ruff", "dev");
project.pyproject_toml().write_file(&manifest_path)?;
}
let mut cmd = Command::new(venv.python_path());
let mut args = vec!["-m", "ruff", "check", "."];
if let Some(it) = config.lint_options.as_ref() {
Expand All @@ -320,6 +346,12 @@ pub fn lint_project(config: &OperationConfig) -> HuakResult<()> {
&mut terminal,
)?;
}
if !project.has_dependency("mypy")?
&& !project.has_optional_dependency("mypy")?
{
project.add_optional_dependency("mypy", "dev");
project.pyproject_toml().write_file(&manifest_path)?;
}
let mut mypy_cmd = Command::new(venv.python_path());
make_venv_command(&mut mypy_cmd, &venv)?;
mypy_cmd
Expand Down Expand Up @@ -390,6 +422,8 @@ pub fn new_lib_project(config: &OperationConfig) -> HuakResult<()> {
/// Publish the Python project to a registry.
pub fn publish_project(config: &OperationConfig) -> HuakResult<()> {
let mut terminal = terminal_from_options(&config.terminal_options);
let manifest_path = config.workspace_root.join("pyproject.toml");
let mut project = Project::from_manifest(&manifest_path)?;
let venv = find_or_create_virtual_environment(config, &mut terminal)?;
if !venv.has_module("twine")? {
venv.install_packages(
Expand All @@ -398,6 +432,12 @@ pub fn publish_project(config: &OperationConfig) -> HuakResult<()> {
&mut terminal,
)?;
}
if !project.has_dependency("twine")?
&& !project.has_optional_dependency("twine")?
{
project.add_optional_dependency("twine", "dev");
project.pyproject_toml().write_file(&manifest_path)?;
}
let mut cmd = Command::new(venv.python_path());
let mut args = vec!["-m", "twine", "upload", "dist/*"];
if let Some(it) = config.publish_options.as_ref() {
Expand All @@ -416,17 +456,16 @@ pub fn remove_project_dependencies(
config: &OperationConfig,
) -> HuakResult<()> {
let mut terminal = terminal_from_options(&config.terminal_options);
let manifest_path = config.workspace_root.join("pyproject.toml");
let mut project = Project::from_manifest(&manifest_path)?;
let venv =
VirtualEnvironment::from_path(find_venv_root(&config.workspace_root)?)?;
let mut project =
Project::from_manifest(config.workspace_root.join("pyproject.toml"))?;

dependency_names.iter().for_each(|item| {
project.remove_dependency(item);
});
venv.uninstall_packages(dependency_names, &mut terminal)?;
project
.pyproject_toml()
.write_file(config.workspace_root.join("pyproject.toml"))
project.pyproject_toml().write_file(&manifest_path)
}

/// Remove a dependency from a Python project.
Expand Down Expand Up @@ -470,6 +509,8 @@ pub fn run_command_str(
/// Run a Python project's tests.
pub fn test_project(config: &OperationConfig) -> HuakResult<()> {
let mut terminal = terminal_from_options(&config.terminal_options);
let manifest_path = config.workspace_root.join("pyproject.toml");
let mut project = Project::from_manifest(&manifest_path)?;
let venv = find_or_create_virtual_environment(config, &mut terminal)?;
if !venv.has_module("pytest")? {
venv.install_packages(
Expand All @@ -478,6 +519,12 @@ pub fn test_project(config: &OperationConfig) -> HuakResult<()> {
&mut terminal,
)?;
}
if !project.has_dependency("pytest")?
&& !project.has_optional_dependency("pytest")?
{
project.add_optional_dependency("pytest", "dev");
project.pyproject_toml.write_file(&manifest_path)?;
}
let mut cmd = Command::new(venv.python_path());
make_venv_command(&mut cmd, &venv)?;
let python_path = if config.workspace_root.join("src").exists() {
Expand Down