Skip to content

Commit 71ef596

Browse files
committed
feat: avoid parsing source code multiple times when patching imports
1 parent e549bed commit 71ef596

2 files changed

Lines changed: 58 additions & 25 deletions

File tree

go-runner/src/builder/patcher.rs

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Patches the imports to use codspeed rather than the official "testing" package.
22
33
use crate::prelude::*;
4+
use itertools::Itertools;
45
use rayon::prelude::*;
56
use std::fs;
67
use std::path::Path;
@@ -69,19 +70,22 @@ pub fn patch_imports<P: AsRef<Path>>(folder: P) -> anyhow::Result<()> {
6970

7071
/// Internal function to apply import patterns to Go source code
7172
pub fn patch_imports_for_source(source: &str) -> String {
72-
let replace_import = |mut source: String, import_path: &str, replacement: &str| -> String {
73+
let mut source = source.to_string();
74+
75+
// If we can't parse the source, skip this replacement
76+
// This can happen with template files or malformed Go code
77+
let parsed = match gosyn::parse_source(&source) {
78+
Ok(p) => p,
79+
Err(_) => return source,
80+
};
81+
82+
let mut replacements = vec![];
83+
let mut find_replace_range = |import_path: &str, replacement: &str| {
7384
// Optimization: check if the import path exists in the source before parsing
7485
if !source.contains(import_path) {
75-
return source;
86+
return;
7687
}
7788

78-
// If we can't parse the source, skip this replacement
79-
// This can happen with template files or malformed Go code
80-
let parsed = match gosyn::parse_source(&source) {
81-
Ok(p) => p,
82-
Err(_) => return source,
83-
};
84-
8589
if let Some(import) = parsed
8690
.imports
8791
.iter()
@@ -90,39 +94,43 @@ pub fn patch_imports_for_source(source: &str) -> String {
9094
let start_pos = import.path.pos;
9195
let end_pos = start_pos + import.path.value.len();
9296

93-
source.replace_range(start_pos..end_pos, replacement);
97+
replacements.push((start_pos..end_pos, replacement.to_string()));
9498
}
95-
96-
source
9799
};
98100

99-
let mut source = replace_import(
100-
source.to_string(),
101-
"testing",
102-
"testing \"github.com/CodSpeedHQ/codspeed-go/testing/testing\"",
103-
);
104-
105101
// Then replace sub-packages like "testing/synctest"
106102
for testing_pkg in &["fstest", "iotest", "quick", "slogtest", "synctest"] {
107-
source = replace_import(
108-
source.to_string(),
103+
find_replace_range(
109104
&format!("testing/{}", testing_pkg),
110105
&format!(
111106
"{testing_pkg} \"github.com/CodSpeedHQ/codspeed-go/testing/testing/{testing_pkg}\""
112107
),
113108
);
114109
}
115110

116-
let source = replace_import(
117-
source,
111+
find_replace_range(
112+
"testing",
113+
"testing \"github.com/CodSpeedHQ/codspeed-go/testing/testing\"",
114+
);
115+
find_replace_range(
118116
"github.com/thejerf/slogassert",
119117
"\"github.com/CodSpeedHQ/codspeed-go/pkg/slogassert\"",
120118
);
121-
replace_import(
122-
source,
119+
find_replace_range(
123120
"github.com/frankban/quicktest",
124121
"\"github.com/CodSpeedHQ/codspeed-go/pkg/quicktest\"",
125-
)
122+
);
123+
124+
// Apply replacements in reverse order to avoid shifting positions
125+
for (range, replacement) in replacements
126+
.into_iter()
127+
.sorted_by_key(|(range, _)| range.start)
128+
.rev()
129+
{
130+
source.replace_range(range, &replacement);
131+
}
132+
133+
source
126134
}
127135

128136
/// Patches imports and package in specific test files
@@ -388,6 +396,17 @@ func BenchmarkExample(b *testing.B) {
388396
func TestExample(t *testing.T) {
389397
s := "package main"
390398
}
399+
"#;
400+
401+
const MANY_TESTING_IMPORTS: &str = r#"package subpackages
402+
import (
403+
"bytes"
404+
"io"
405+
"testing"
406+
"testing/fstest"
407+
"testing/iotest"
408+
"testing/synctest"
409+
)
391410
"#;
392411

393412
#[rstest]
@@ -406,6 +425,7 @@ func TestExample(t *testing.T) {
406425
MULTILINE_IMPORT_WITH_TESTING_STRING
407426
)]
408427
#[case("package_main", PACKAGE_MAIN)]
428+
#[case("many_testing_imports", MANY_TESTING_IMPORTS)]
409429
fn test_patch_go_source(#[case] test_name: &str, #[case] source: &str) {
410430
let result = patch_imports_for_source(source);
411431
let result = patch_package_for_source(result).unwrap();
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
source: go-runner/src/builder/patcher.rs
3+
expression: result
4+
---
5+
package subpackages
6+
import (
7+
"bytes"
8+
"io"
9+
testing "github.com/CodSpeedHQ/codspeed-go/testing/testing"
10+
fstest "github.com/CodSpeedHQ/codspeed-go/testing/testing/fstest"
11+
iotest "github.com/CodSpeedHQ/codspeed-go/testing/testing/iotest"
12+
synctest "github.com/CodSpeedHQ/codspeed-go/testing/testing/synctest"
13+
)

0 commit comments

Comments
 (0)