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

Evaluating usages for build artifacts of Gradle projects #20

Merged
merged 1 commit into from
Apr 11, 2024
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
104 changes: 101 additions & 3 deletions src/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,45 @@

use crate::models::{AllocatedResource, DiskCached, UseCase};
use itertools::Itertools;
use std::path::Path;
use std::path::{Path, PathBuf};
use ubyte::ByteUnit;
use walkdir::{DirEntry, WalkDir};

pub fn usage_for_gradle_projects(projects: &[PathBuf]) -> anyhow::Result<AllocatedResource> {
let use_case = UseCase::from(DiskCached::BuildOutputForGradleProject);
let allocated = projects
.iter()
.map(|project| usage_for_gradle_project(project.as_path()))
.collect::<anyhow::Result<Vec<AllocatedResource>>>()?;

let total_amount = allocated
.iter()
.fold(ByteUnit::from(0), |total, allocation| total + allocation.amount);

Ok(AllocatedResource::new(use_case, total_amount))
}

fn usage_for_gradle_project(gradle_project: &Path) -> anyhow::Result<AllocatedResource> {
let use_case = UseCase::from(DiskCached::BuildOutputForGradleProject);

let Ok(true) = gradle_project.try_exists() else {
return Ok(AllocatedResource::new(use_case, ByteUnit::from(0)));
};

let total = WalkDir::new(gradle_project)
.into_iter()
.filter_map(|entry| entry.ok())
.filter(ensure_build_output_file)
.map(|entry| size_for_entry(&entry))
.sum::<u64>();

Ok(AllocatedResource::new(use_case, ByteUnit::from(total)))
}

pub fn usage_for_maven_local(maven_local: &Path) -> anyhow::Result<AllocatedResource> {
// We trust that gradle_home == $HOME/.m2
// We trust that M2 local repository lives under $HOME/.m2
let use_case = UseCase::from(DiskCached::MavenLocalStorage);

let Ok(true) = maven_local.try_exists() else {
return Ok(AllocatedResource::new(use_case, ByteUnit::from(0)));
};
Expand Down Expand Up @@ -57,6 +89,18 @@ fn ensure_file(entry: &DirEntry) -> bool {
.is_file()
}

fn ensure_build_output_file(entry: &DirEntry) -> bool {
let path = entry.path().to_str().expect("Expecting a valid path");
let build_output = path.contains("build/");

let build_output_file = entry
.metadata()
.expect("Expecting a valid metadata for entry")
.is_file();

build_output && build_output_file
}

fn evaluate_use_case_from_gradle_home(entry: &DirEntry) -> UseCase {
let raw_path = entry
.path()
Expand All @@ -82,7 +126,7 @@ fn evaluate_use_case_from_gradle_home(entry: &DirEntry) -> UseCase {

#[cfg(test)]
mod tests {
use crate::disk::{usage_for_gradle_home, usage_for_maven_local};
use crate::disk::{usage_for_gradle_home, usage_for_gradle_projects, usage_for_maven_local};
use crate::models::{AllocatedResource, DiskCached, UseCase};
use fake::{Fake, StringFaker};
use std::fs;
Expand All @@ -109,6 +153,29 @@ mod tests {
}
}

fn prepare_fake_gradle_projects(dir: &TempDir) {
let folders = vec![
"AndroidStudioProjects",
"AndroidStudioProjects/my-project",
"AndroidStudioProjects/my-project/build",
];

for folder in folders {
fs::create_dir(dir.path().join(folder)).expect("Cant create temporary fixture folder");
}

let files = vec![
"AndroidStudioProjects/my-project/settings.gradle",
"AndroidStudioProjects/my-project/build.gradle",
"AndroidStudioProjects/my-project/gradlew",
"AndroidStudioProjects/my-project/gradle.properties",
];

for file in files {
fs::write(dir.path().join(file), "foo").expect("Cant create fixture file");
}
}

fn create_fake_1kb_file(gradle_home: &TempDir, folder: &str) {
let file_name = Uuid::new_v4();
let relative_path = format!("{}/{}", folder, file_name);
Expand Down Expand Up @@ -190,4 +257,35 @@ mod tests {
let expected = AllocatedResource::new(use_case, 2.kilobytes());
assert_eq!(usage, expected)
}

#[test]
fn should_compute_no_resources_when_missing_gradle_projects() {
let temp_dir = TempDir::new().expect("Cant create temp dir");
let fake_android_studio_projects_path = vec![temp_dir.path().to_path_buf()];

let usage = usage_for_gradle_projects(&fake_android_studio_projects_path).expect("Cannot compute use cases");

let use_case = UseCase::from(DiskCached::BuildOutputForGradleProject);
let expected = AllocatedResource::new(use_case, ByteUnit::from(0));
assert_eq!(usage, expected)
}

#[test]
fn should_compute_resources_when_gradle_projects_present() {
let temp_dir = TempDir::new().expect("Cant create temp dir");

prepare_fake_gradle_projects(&temp_dir);

for _ in 0..5 {
create_fake_1kb_file(&temp_dir, "AndroidStudioProjects/my-project/build");
}

let fake_android_studio_projects_path = vec![temp_dir.path().to_path_buf()];

let usage = usage_for_gradle_projects(&fake_android_studio_projects_path).expect("Cannot compute use cases");

let use_case = UseCase::from(DiskCached::BuildOutputForGradleProject);
let expected = AllocatedResource::new(use_case, 5.kilobytes());
assert_eq!(usage, expected)
}
}
55 changes: 54 additions & 1 deletion src/filesystem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

use anyhow::anyhow;
use directories::BaseDirs;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use walkdir::{DirEntry, WalkDir};

pub fn find_gradle_home() -> anyhow::Result<PathBuf> {
let base_dir = BaseDirs::new().ok_or(anyhow!("Cannot access base directories"))?;
Expand All @@ -16,3 +17,55 @@ pub fn find_maven_local_repository() -> anyhow::Result<PathBuf> {
let home_dir = base_dir.home_dir();
Ok(home_dir.join(".m2"))
}

pub fn find_all_gradle_projects() -> anyhow::Result<Vec<PathBuf>> {
let base_dir = BaseDirs::new().ok_or(anyhow!("Cannot access base directories"))?;
let home_dir = base_dir.home_dir();

let android_studio_projects_folder = home_dir.join("AndroidStudioProjects");
let android_projects = find_gradle_projects(android_studio_projects_folder.as_path())?;

let intellij_projects_folder = home_dir.join("IdeaProjects");
let jvm_projects = find_gradle_projects(intellij_projects_folder.as_path())?;

let mut all_projects: Vec<PathBuf> = Vec::new();
all_projects.extend(android_projects);
all_projects.extend(jvm_projects);

Ok(all_projects)
}

fn find_gradle_projects(folder: &Path) -> anyhow::Result<Vec<PathBuf>> {
let projects = WalkDir::new(folder)
.into_iter()
.filter_map(|entry| entry.ok())
.filter(ensure_gradle_project)
.map(|entry| entry.into_path())
.collect::<Vec<_>>();

Ok(projects)
}

fn ensure_gradle_project(entry: &DirEntry) -> bool {
let project_root = entry.path();

let settings_file_groovy = project_root.join("settings.gradle");
let settings_file_kotlin = project_root.join("settings.gradle.kts");
let has_top_level_settings_config = settings_file_groovy.exists() || settings_file_kotlin.exists();

let build_file_groovy = project_root.join("build.gradle");
let build_file_kotlin = project_root.join("build.gradle.kts");
let has_top_level_build_config = build_file_groovy.exists() || build_file_kotlin.exists();

let has_top_level_gradlew = project_root.join("gradlew").exists();
let has_top_level_gradle_properties = project_root.join("gradle.properties").exists();

let verifications = vec![
has_top_level_build_config,
has_top_level_settings_config,
has_top_level_gradlew,
has_top_level_gradle_properties,
];

verifications.into_iter().all(|check| check)
}
4 changes: 1 addition & 3 deletions src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
use std::fmt::{Display, Formatter};
use ubyte::ByteUnit;

#[allow(dead_code)]
#[derive(Debug)]
pub enum MachineResource {
RamMemory,
Expand Down Expand Up @@ -39,7 +38,6 @@ impl Display for MemoryCached {
}
}

#[allow(dead_code)]
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord)]
pub enum DiskCached {
GradleConfigurationCaching,
Expand Down Expand Up @@ -67,7 +65,7 @@ impl Display for DiskCached {
DiskCached::GradleNativeFiles => "Gradle platform-native caches",
DiskCached::GradleBuildScans => "Gradle build-scans data",
DiskCached::GradleOtherFiles => "Other files on Gradle Home",
DiskCached::BuildOutputForGradleProject => "Build output on Gradle projects",
DiskCached::BuildOutputForGradleProject => "Build artifacts on projects",
DiskCached::MavenLocalStorage => "Maven local repository",
};

Expand Down
12 changes: 8 additions & 4 deletions src/wiper.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Copyright 2024 Dotanuki Labs
// SPDX-License-Identifier: MIT

use crate::disk::{usage_for_gradle_home, usage_for_maven_local};
use crate::filesystem::{find_gradle_home, find_maven_local_repository};
use crate::disk::{usage_for_gradle_home, usage_for_gradle_projects, usage_for_maven_local};
use crate::filesystem::{find_all_gradle_projects, find_gradle_home, find_maven_local_repository};
use crate::models::{AllocatedResource, EvaluationOutcome, ExecutionOutcome, MachineResource, WipeAction};
use ubyte::{ByteUnit, ToByteUnit};
use MachineResource::{DiskSpace, RamMemory};
Expand Down Expand Up @@ -43,12 +43,16 @@ fn evaluate_disk_space() -> anyhow::Result<ExecutionOutcome> {
let maven_local_resources = usage_for_maven_local(maven_local_repository.as_path())?;
let total_size_for_maven_local = maven_local_resources.amount;

let gradle_projects = find_all_gradle_projects()?;
let gradle_projects_resources = usage_for_gradle_projects(&gradle_projects)?;
let total_size_for_gradle_projects = gradle_projects_resources.amount;

let mut disk_resources: Vec<AllocatedResource> = Vec::new();
disk_resources.extend(gradle_home_resources);
disk_resources.push(maven_local_resources);
disk_resources.push(gradle_projects_resources);

let total_size_on_disk = total_size_for_gradle_home + total_size_for_maven_local;

let total_size_on_disk = total_size_for_gradle_home + total_size_for_maven_local + total_size_for_gradle_projects;
let outcome = EvaluationOutcome::new(disk_resources, total_size_on_disk);
Ok(ExecutionOutcome::Evaluation(outcome))
}
Expand Down