use anyhow::{anyhow, bail, Result};
use std::path::{Path, PathBuf};
use tracing::info;
use walkdir::DirEntry;
use crate::{
api::releases::{Release, ReleaseBuilder},
sourcemaps::{
content::SourceMapFile,
source_pairs::{read_pairs, SourcePair},
},
utils::git::get_git_info,
};
#[derive(clap::Args)]
pub struct InjectArgs {
#[arg(short, long)]
pub directory: PathBuf,
#[arg(short, long)]
pub public_path_prefix: Option<String>,
#[arg(short, long)]
pub ignore: Vec<String>,
#[arg(long)]
pub project: Option<String>,
#[arg(long)]
pub version: Option<String>,
}
pub fn inject_impl(args: &InjectArgs, matcher: impl Fn(&DirEntry) -> bool) -> Result<()> {
let InjectArgs {
directory,
public_path_prefix,
ignore,
project,
version,
} = args;
let directory = directory.canonicalize().map_err(|e| {
anyhow!(
"Directory '{}' not found or inaccessible: {}",
directory.display(),
e
)
})?;
info!("injecting directory: {}", directory.display());
let mut pairs = read_pairs(&directory, ignore, matcher, public_path_prefix)?;
if pairs.is_empty() {
bail!("no source files found");
}
let created_release_id = get_release_for_maps(
&directory,
project,
version,
pairs.iter().map(|p| &p.sourcemap),
)?
.as_ref()
.map(|r| r.id.to_string());
pairs = inject_pairs(pairs, created_release_id)?;
for pair in &pairs {
pair.save()?;
}
info!("injecting done");
Ok(())
}
pub fn inject_pairs(
mut pairs: Vec<SourcePair>,
created_release_id: Option<String>,
) -> Result<Vec<SourcePair>> {
for pair in &mut pairs {
let current_release_id = pair.get_release_id();
if current_release_id != created_release_id || pair.get_chunk_id().is_none() {
pair.set_release_id(created_release_id.clone());
let chunk_id = uuid::Uuid::now_v7().to_string();
if let Some(previous_chunk_id) = pair.get_chunk_id() {
pair.update_chunk_id(previous_chunk_id, chunk_id)?;
} else {
pair.add_chunk_id(chunk_id)?;
}
}
}
Ok(pairs)
}
pub fn get_release_for_maps<'a>(
directory: &Path,
project: &Option<String>,
version: &Option<String>,
maps: impl IntoIterator<Item = &'a SourceMapFile>,
) -> Result<Option<Release>> {
let needs_release =
project.is_some() || version.is_some() || maps.into_iter().any(|p| !p.has_release_id());
let mut created_release = None;
if needs_release {
let mut builder = get_git_info(Some(directory.to_path_buf()))?
.map(ReleaseBuilder::init_from_git)
.unwrap_or_default();
if let Some(project) = project {
builder.with_project(project);
}
if let Some(version) = version {
builder.with_version(version);
}
if builder.can_create() {
created_release = Some(builder.fetch_or_create()?);
}
}
Ok(created_release)
}