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::{
9 content::SourceMapFile,
10 source_pairs::{read_pairs, SourcePair},
11 },
12 utils::git::get_git_info,
13};
14
15#[derive(clap::Args)]
16pub struct InjectArgs {
17 #[arg(short, long)]
19 pub directory: PathBuf,
20
21 #[arg(short, long)]
25 pub public_path_prefix: Option<String>,
26
27 #[arg(short, long)]
29 pub ignore: Vec<String>,
30
31 #[arg(long)]
35 pub project: Option<String>,
36
37 #[arg(long)]
41 pub version: Option<String>,
42}
43
44pub fn inject_impl(args: &InjectArgs, matcher: impl Fn(&DirEntry) -> bool) -> Result<()> {
45 let InjectArgs {
46 directory,
47 public_path_prefix,
48 ignore,
49 project,
50 version,
51 } = args;
52
53 let directory = directory.canonicalize().map_err(|e| {
54 anyhow!(
55 "Directory '{}' not found or inaccessible: {}",
56 directory.display(),
57 e
58 )
59 })?;
60
61 info!("injecting directory: {}", directory.display());
62 let mut pairs = read_pairs(&directory, ignore, matcher, public_path_prefix)?;
63 if pairs.is_empty() {
64 bail!("no source files found");
65 }
66
67 let created_release_id = get_release_for_maps(
68 &directory,
69 project,
70 version,
71 pairs.iter().map(|p| &p.sourcemap),
72 )?
73 .as_ref()
74 .map(|r| r.id.to_string());
75
76 pairs = inject_pairs(pairs, created_release_id)?;
77
78 for pair in &pairs {
80 pair.save()?;
81 }
82 info!("injecting done");
83 Ok(())
84}
85
86pub fn inject_pairs(
87 mut pairs: Vec<SourcePair>,
88 created_release_id: Option<String>,
89) -> Result<Vec<SourcePair>> {
90 for pair in &mut pairs {
91 let current_release_id = pair.get_release_id();
92 if current_release_id != created_release_id || pair.get_chunk_id().is_none() {
94 pair.set_release_id(created_release_id.clone());
95
96 let chunk_id = uuid::Uuid::now_v7().to_string();
97 if let Some(previous_chunk_id) = pair.get_chunk_id() {
98 pair.update_chunk_id(previous_chunk_id, chunk_id)?;
99 } else {
100 pair.add_chunk_id(chunk_id)?;
101 }
102 }
103 }
104
105 Ok(pairs)
106}
107
108pub fn get_release_for_maps<'a>(
109 directory: &Path,
110 project: &Option<String>,
111 version: &Option<String>,
112 maps: impl IntoIterator<Item = &'a SourceMapFile>,
113) -> Result<Option<Release>> {
114 let needs_release =
117 project.is_some() || version.is_some() || maps.into_iter().any(|p| !p.has_release_id());
118
119 let mut created_release = None;
120 if needs_release {
121 let mut builder = get_git_info(Some(directory.to_path_buf()))?
122 .map(ReleaseBuilder::init_from_git)
123 .unwrap_or_default();
124
125 if let Some(project) = project {
126 builder.with_project(project);
127 }
128 if let Some(version) = version {
129 builder.with_version(version);
130 }
131
132 if builder.can_create() {
133 created_release = Some(builder.fetch_or_create()?);
134 }
135 }
136
137 Ok(created_release)
138}