posthog_cli/sourcemaps/
inject.rs1use anyhow::{anyhow, bail, Result};
2use std::path::{Path, PathBuf};
3use tracing::info;
4use walkdir::DirEntry;
5
6use crate::{
7 api::releases::{Release, ReleaseBuilder},
8 sourcemaps::source_pairs::{read_pairs, SourcePair},
9 utils::git::get_git_info,
10};
11
12#[derive(clap::Args)]
13pub struct InjectArgs {
14 #[arg(short, long)]
16 pub directory: PathBuf,
17
18 #[arg(short, long)]
22 pub public_path_prefix: Option<String>,
23
24 #[arg(short, long)]
26 pub ignore: Vec<String>,
27
28 #[arg(long)]
32 pub project: Option<String>,
33
34 #[arg(long)]
37 pub version: Option<String>,
38}
39
40pub fn inject_impl(args: &InjectArgs, matcher: impl Fn(&DirEntry) -> bool) -> Result<()> {
41 let InjectArgs {
42 directory,
43 public_path_prefix,
44 ignore,
45 project,
46 version,
47 } = args;
48
49 let directory = directory.canonicalize().map_err(|e| {
50 anyhow!(
51 "Directory '{}' not found or inaccessible: {}",
52 directory.display(),
53 e
54 )
55 })?;
56
57 info!("Processing directory: {}", directory.display());
58 let mut pairs = read_pairs(&directory, ignore, matcher, public_path_prefix)?;
59 if pairs.is_empty() {
60 bail!("No source files found");
61 }
62 info!("Found {} pairs", pairs.len());
63
64 let created_release_id = get_release_for_pairs(&directory, project, version, &pairs)?
65 .as_ref()
66 .map(|r| r.id.to_string());
67
68 pairs = inject_pairs(pairs, created_release_id)?;
69
70 for pair in &pairs {
72 pair.save()?;
73 }
74 info!("Finished processing directory");
75 Ok(())
76}
77
78pub fn inject_pairs(
79 mut pairs: Vec<SourcePair>,
80 created_release_id: Option<String>,
81) -> Result<Vec<SourcePair>> {
82 for pair in &mut pairs {
83 let current_release_id = pair.get_release_id();
84 if current_release_id != created_release_id || pair.get_chunk_id().is_none() {
86 pair.set_release_id(created_release_id.clone());
87
88 let chunk_id = uuid::Uuid::now_v7().to_string();
89 if let Some(previous_chunk_id) = pair.get_chunk_id() {
90 pair.update_chunk_id(previous_chunk_id, chunk_id)?;
91 } else {
92 pair.add_chunk_id(chunk_id)?;
93 }
94 }
95 }
96
97 Ok(pairs)
98}
99
100pub fn get_release_for_pairs<'a>(
101 directory: &Path,
102 project: &Option<String>,
103 version: &Option<String>,
104 pairs: impl IntoIterator<Item = &'a SourcePair>,
105) -> Result<Option<Release>> {
106 let needs_release =
109 project.is_some() || version.is_some() || pairs.into_iter().any(|p| !p.has_release_id());
110
111 let mut created_release = None;
112 if needs_release {
113 let mut builder = get_git_info(Some(directory.to_path_buf()))?
114 .map(ReleaseBuilder::init_from_git)
115 .unwrap_or_default();
116
117 if let Some(project) = project {
118 builder.with_project(project);
119 }
120 if let Some(version) = version {
121 builder.with_version(version);
122 }
123
124 if builder.can_create() {
125 created_release = Some(builder.fetch_or_create()?);
126 }
127 }
128
129 Ok(created_release)
130}