Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
121 commits
Select commit Hold shift + click to select a range
7276e6e
Add Components to core
DmitryAstafyev Mar 21, 2025
9eb1b62
Introduce sources and parsers as components
DmitryAstafyev Mar 26, 2025
a6427fc
Update components API
DmitryAstafyev Mar 27, 2025
806d0e9
Correct protocol (components context)
DmitryAstafyev Mar 27, 2025
46328ba
Update components controller (public events)
DmitryAstafyev Mar 28, 2025
f16867c
Consider canelation order (fields)
DmitryAstafyev Mar 28, 2025
0ace808
Add options to parsers for tests
DmitryAstafyev Mar 28, 2025
090f1ed
Update jasmine test
DmitryAstafyev Mar 28, 2025
6cc3dd2
Update lock files
DmitryAstafyev Mar 28, 2025
3629aad
Revert test data changes
DmitryAstafyev Mar 28, 2025
f9b769b
Change signatures for events
DmitryAstafyev Mar 31, 2025
c613da8
Resolve rebase conflicts
DmitryAstafyev Mar 31, 2025
05404ca
Refactoring (switch to descriptor)
DmitryAstafyev Apr 1, 2025
650e682
Update code on upper core levels
DmitryAstafyev Apr 1, 2025
6e84834
Add basic docs and small renaming
DmitryAstafyev Apr 2, 2025
84c0277
Provide validation fields API
DmitryAstafyev Apr 7, 2025
ed57a17
Update types for options
DmitryAstafyev Apr 8, 2025
697adf5
Binding for all layers
DmitryAstafyev Apr 9, 2025
f828546
Add settings scheme to serial port (backend)
DmitryAstafyev Apr 23, 2025
ff05480
Basic template or setup tab
DmitryAstafyev Apr 23, 2025
5a49cb9
Bindins between settings fields
DmitryAstafyev Apr 28, 2025
ea6279f
Remove special bound field component
DmitryAstafyev Apr 28, 2025
352def4
Introduce nested dictionary element
DmitryAstafyev Apr 30, 2025
7ce2b14
Delivery dlt statistic with new API
DmitryAstafyev May 4, 2025
ac46783
Refactoring element definition
DmitryAstafyev May 5, 2025
195e1b0
Add files selector element
DmitryAstafyev May 5, 2025
4720a87
Update compatible-filter
DmitryAstafyev May 6, 2025
c715a54
Remove observe calls / switch to origin usage
DmitryAstafyev May 6, 2025
863fb37
Parser/Source API refactoring (step 1)
DmitryAstafyev May 8, 2025
6c1f9e2
Switch LogMessage to enum
DmitryAstafyev May 9, 2025
e900940
Create parser/source from components
DmitryAstafyev May 12, 2025
2b6a8cb
Remove async-trait to use allow(async_fn_in_trait)
DmitryAstafyev May 12, 2025
756bb4c
Add test drive runner (testing updated interfaces)
DmitryAstafyev May 13, 2025
2602469
Remove generic type from Source definition
DmitryAstafyev May 14, 2025
02d0ac7
Using writer in parser
DmitryAstafyev May 16, 2025
17edc13
Introduce LogRecordOutput
DmitryAstafyev May 16, 2025
f59cd97
Restore min_msg_len as parser method
DmitryAstafyev May 19, 2025
768e60a
Move MessageProducer out of sources
DmitryAstafyev May 19, 2025
667b1ea
Change source description representation
DmitryAstafyev May 19, 2025
9dd5c75
Add documentation and cleanup
DmitryAstafyev May 19, 2025
74c7897
Upgrade export function
DmitryAstafyev May 20, 2025
47e49f1
Fix executing of application
DmitryAstafyev May 20, 2025
1d5beff
Corrections in the scope of rebasing to plugins branch (master)
DmitryAstafyev May 21, 2025
624d4ca
Add documentation and reanaming
DmitryAstafyev May 22, 2025
4e3cac7
Merge observe operation and exporting raw operation
DmitryAstafyev May 22, 2025
210eb5b
Add timezone selector
DmitryAstafyev May 27, 2025
9a4ebe5
Update SomeIp descriptor
DmitryAstafyev May 27, 2025
2f4e27c
Allow collection of fields
DmitryAstafyev May 29, 2025
eef20f1
Update options of components
DmitryAstafyev May 29, 2025
de6bf45
Update UDP options; link nested elements with parent
DmitryAstafyev May 29, 2025
197aa8d
Sync error handeling between rustcore and client (nested fields)
DmitryAstafyev Jun 1, 2025
7371142
Update layout of fields
DmitryAstafyev Jun 3, 2025
0091b03
Update descriptions
DmitryAstafyev Jun 4, 2025
5af5bfa
Allow session starting (Test drive mode)
DmitryAstafyev Jun 4, 2025
2d78951
Add render and IO type options
DmitryAstafyev Jun 5, 2025
640322f
Render related bindings
DmitryAstafyev Jun 5, 2025
0b3401f
Fix MessageProducer loop
DmitryAstafyev Jun 6, 2025
d1f518f
Add IO compatibility checks
DmitryAstafyev Jun 6, 2025
691bcee
Fix session writer (sync reading and UI updates)
DmitryAstafyev Jun 9, 2025
246cb88
Update setting of command source
DmitryAstafyev Jun 9, 2025
0f1cede
Add documentation to components and definitions
DmitryAstafyev Jun 10, 2025
1b97881
Fix merge conflicts
DmitryAstafyev Jun 12, 2025
8c6bd04
Remove unused lock file
DmitryAstafyev Jun 12, 2025
d86ff19
Extend configuration
DmitryAstafyev Jun 12, 2025
76e8a5b
Update descriptors for parsers and sources
DmitryAstafyev Jun 12, 2025
508f89b
Update dicionary config components
DmitryAstafyev Jun 13, 2025
a6450da
Fix error on parser iterator
DmitryAstafyev Jun 18, 2025
4302fce
Extend components API
DmitryAstafyev Jun 23, 2025
aa0fbe7
Extend SessionDescriptor with more data
DmitryAstafyev Jun 25, 2025
cac2817
Renaming
DmitryAstafyev Jun 25, 2025
c6cf557
Add SessionDescriptor event
DmitryAstafyev Jun 25, 2025
029f8f7
Change Parser definitions & Plugins integrations
AmmarAbouZor Jun 25, 2025
d7d6d61
Adjust LogRecordWriter definitions & implementations
AmmarAbouZor Jun 27, 2025
f003f36
Run CI checks on PRs into master only
AmmarAbouZor Jun 24, 2025
060e0cb
After Review: LogRecordWriter -> LogRecordsBuffer
AmmarAbouZor Jul 1, 2025
9279da4
Components: Move Plugins Manger to component session
AmmarAbouZor Jul 1, 2025
aa9af8c
Components: Move plugins API calls in bindings
AmmarAbouZor Jul 1, 2025
ef63506
Components: Integrate Plugins in Electron
AmmarAbouZor Jul 1, 2025
42ef787
Components: Plugins Integrations in system
AmmarAbouZor Jul 3, 2025
8d4544a
Add SessionDescriptor into session (client)
DmitryAstafyev Jun 25, 2025
e2dc390
Remove SourceObserve and Observe from session
DmitryAstafyev Jul 1, 2025
5ad915d
Remove Observe interface and class
DmitryAstafyev Jul 4, 2025
0060c03
Resolve conflict on sources tracker
DmitryAstafyev Jul 6, 2025
abc6970
Fix jobs definition
DmitryAstafyev Jul 7, 2025
fca8ddf
Update recent actions format
DmitryAstafyev Jul 7, 2025
814f43d
Update recent action provider
DmitryAstafyev Jul 7, 2025
0ab2c1c
Fix events validation on ts-bindings layer
DmitryAstafyev Jul 8, 2025
fcbd519
Correct history source definitions
DmitryAstafyev Jul 10, 2025
fe39131
Correct recent actions checks
DmitryAstafyev Jul 10, 2025
95a1146
Resolve part of not implemented points
DmitryAstafyev Jul 11, 2025
8890fb1
Fix view of recent actions
DmitryAstafyev Jul 14, 2025
0e3656e
Remove manual validation of types of rust events
DmitryAstafyev Jul 15, 2025
d037b4d
Add active/inactive observe lists
DmitryAstafyev Jul 15, 2025
ba9d151
Fix source definition parsing
DmitryAstafyev Jul 15, 2025
9ad574e
Change source ids format and processing
DmitryAstafyev Jul 16, 2025
20d12f5
Upgrade Components - less abstraction
DmitryAstafyev Jul 18, 2025
6f5672b
Remove enum from Components
DmitryAstafyev Jul 18, 2025
82ec659
Rename Components to Register
DmitryAstafyev Jul 18, 2025
593ef0f
Restore parsers/sources unit tests
DmitryAstafyev Jul 21, 2025
dc35833
Replace components crate with descriptor crate
DmitryAstafyev Jul 21, 2025
87a20b4
Restore session parser/source snap tests
DmitryAstafyev Jul 22, 2025
d6b5b9e
Update a documentation to code
DmitryAstafyev Jul 23, 2025
028b2f1
Restore dlt-tools tests
DmitryAstafyev Jul 23, 2025
76d3ce1
Fix running of sources tests
DmitryAstafyev Jul 23, 2025
c9f385f
Update sources unit tests
DmitryAstafyev Jul 23, 2025
60463f1
Move bench tests to session
DmitryAstafyev Jul 24, 2025
435cbb4
Move register to own crate
DmitryAstafyev Jul 24, 2025
f7ee07f
Adopt plugins to updated register
DmitryAstafyev Jul 24, 2025
0a0fefe
Partly resolve clippy warns
DmitryAstafyev Jul 24, 2025
d6d160c
Restore get_components method
DmitryAstafyev Jul 25, 2025
73dca6f
Add SDE support API (close #2365)
DmitryAstafyev Jul 25, 2025
494f10b
Add API: get default options & compatible setup
DmitryAstafyev Jul 30, 2025
abdaffd
Move factory back to trait
DmitryAstafyev Aug 4, 2025
c23f37b
Fix an issue with stream reference in observed list
DmitryAstafyev Aug 6, 2025
9827e19
Put color of source back into observed list
DmitryAstafyev Aug 6, 2025
724315d
Fix source color linking
DmitryAstafyev Aug 7, 2025
0598663
Switch to indexed map (Register)
DmitryAstafyev Aug 11, 2025
31144b3
Fix for API access on session configure
DmitryAstafyev Aug 12, 2025
6f8bcf3
Provide popup with attaching (draft)
DmitryAstafyev Aug 12, 2025
daf6fc5
Fix dialogs and allow attaching observe operations
DmitryAstafyev Aug 13, 2025
df89574
Add IO compatible sources list
DmitryAstafyev Aug 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 4 additions & 2 deletions .github/workflows/pullrequest_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ on:

jobs:
ts_and_rust_lint:
if: github.event.pull_request.draft == false
# TODO AAZ: Make sure this check works upon merging into master.
if: github.event.pull_request.draft == false && github.event.pull_request.base.ref == 'master'
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand Down Expand Up @@ -63,7 +64,8 @@ jobs:
run: yarn run check

integration_and_unit_tests:
if: github.event.pull_request.draft == false
# TODO AAZ: Make sure this check works upon merging into master.
if: github.event.pull_request.draft == false && github.event.pull_request.base.ref == 'master'
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[![](https://github.com/esrlabs/chipmunk/actions/workflows/release_next.yml/badge.svg)](https://github.com/esrlabs/chipmunk/actions/workflows/release_next.yml)
[![](https://github.com/esrlabs/chipmunk/actions/workflows/lint_master.yml/badge.svg)](https://github.com/esrlabs/chipmunk/actions/workflows/lint_master.yml)

`chipmunk` is one of the fastest desktop applications for viewing log files, with no limitations on file size. 1 GB, 2 GB, 10 GB? `chipmunk` is limited only by your disk space nothing more. With no caching and no unnecessary copying, files of any size open with the same speed. But `chipmunk` goes beyond just working with files: it also allows you to create network connections to collect logs via TCP, UDP, Serial, or from the output of a running command.
`chipmunk` is one of the fastest desktop applications for viewing log files, with no limitations on file size. 1 GB, 2 GB, 10 GB? `chipmunk` is limited only by your disk space - nothing more. With no caching and no unnecessary copying, files of any size open with the same speed. But `chipmunk` goes beyond just working with files: it also allows you to create network connections to collect logs via TCP, UDP, Serial, or from the output of a running command.

## Automotive and Network Traces

Expand All @@ -19,7 +19,7 @@ Additionally, `chipmunk` allows you to work with DLT traces both as standalone f
- Serial Port
- Output from a command or program

For each source, you can assign a parser for example, to collect DLT packets over a UDP connection for analysis or to save them as a standalone trace file.
For each source, you can assign a parser - for example, to collect DLT packets over a UDP connection for analysis or to save them as a standalone trace file.

Another key feature is the ability to launch any command or program and collect its output, which can be analyzed in real time as it's generated.

Expand All @@ -29,7 +29,7 @@ At its core, `chipmunk` is a log analysis tool. It goes beyond simple search que

![filters_create](./docs/assets/search/filters_create.gif)

The search engine works dynamically results are updated in real time as new data is added. If you're connected to a live data source, your active filters will continuously update the search results as new logs arrive.
The search engine works dynamically - results are updated in real time as new data is added. If you're connected to a live data source, your active filters will continuously update the search results as new logs arrive.

## Metrics, Measurements, and Graphs

Expand All @@ -47,6 +47,6 @@ See more details in the [documentation](https://esrlabs.github.io/chipmunk/) abo

## Contributing

We welcome contributions of all kinds bug reports, performance improvements, documentation fixes, or new features.
We welcome contributions of all kinds - bug reports, performance improvements, documentation fixes, or new features.

[Click here to view it](https://esrlabs.github.io/chipmunk/contributing/welcome/)
5 changes: 5 additions & 0 deletions application/apps/indexer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ members = [
"addons/file-tools",
"addons/text_grep",
"addons/bufread",
"descriptor",
"register",
"indexer_base",
"merging",
"parsers",
Expand Down Expand Up @@ -42,6 +44,9 @@ envvars = "0.1"
anyhow = "1.0"
toml = "0.8"
blake3 = "1.8"
serialport = "4.6"
etherparse = "0.18"
indexmap = "2.10"

## Development Dependencies ##
# Support for `html_reports` needs running the benchmarks via `cargo-criterion` tool.
Expand Down
10 changes: 7 additions & 3 deletions application/apps/indexer/addons/dlt-tools/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ edition = "2024"

[dependencies]
dlt-core.workspace = true
indexer_base = { path = "../../indexer_base" }
log.workspace = true
parsers = { path = "../../parsers" }
sources = { path = "../../sources" }
tokio = { workspace = true , features = ["full"] }
tokio-util = { workspace = true, features = ["codec", "net"] }
indexer_base = { path = "../../indexer_base" }
parsers = { path = "../../parsers" }
sources = { path = "../../sources" }
processor = { path = "../../processor" }
stypes = { path = "../../stypes" }
session = { path = "../../session" }
uuid.workspace = true

[dev-dependencies]
195 changes: 97 additions & 98 deletions application/apps/indexer/addons/dlt-tools/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![deny(unused_crate_dependencies)]
// #![deny(unused_crate_dependencies)]
// Copyright (c) 2019 E.S.R.Labs. All rights reserved.
//
// NOTICE: All information contained herein is, and remains
Expand All @@ -10,81 +10,104 @@
// Dissemination of this information or reproduction of this material
// is strictly forbidden unless prior written permission is obtained
// from E.S.R.Labs.
extern crate indexer_base;

#[macro_use]
extern crate log;

use dlt_core::filtering::DltFilterConfig;
use parsers::{Attachment, MessageStreamItem, ParseYield, dlt::DltParser};
use sources::{binary::raw::BinaryByteSource, producer::MessageProducer};
use parsers::api::*;
use processor::producer::{MessageProducer, MessageStreamItem};
use session::session::Session;
use std::{
collections::HashMap,
fs::File,
io::{BufReader, BufWriter, Write},
io::{BufWriter, Write},
path::{Path, PathBuf},
};
use stypes::{SessionAction, SessionSetup};
use tokio_util::sync::CancellationToken;
use uuid::Uuid;

#[derive(Default)]
pub struct AttachmentsCollector {
pub attachments: Vec<Attachment>,
messages: usize,
}

impl LogRecordsBuffer for AttachmentsCollector {
fn append(&mut self, record: LogRecordOutput<'_>) {
match record {
LogRecordOutput::Raw(..)
| LogRecordOutput::Message(..)
| LogRecordOutput::Columns(..) => {
self.messages += 1;
}
LogRecordOutput::Multiple(inner) => {
for rec in inner {
self.append(rec);
}
}
LogRecordOutput::Attachment(inner) => {
self.attachments.push(inner);
}
}
}

async fn flush(&mut self) -> Result<(), stypes::NativeError> {
Ok(())
}

fn get_source_id(&self) -> u16 {
0
}
}

pub async fn scan_dlt_ft(
input: PathBuf,
filter: Option<DltFilterConfig>,
with_storage_header: bool,
filename: PathBuf,
filters: Option<HashMap<String, Vec<String>>>,
cancel: CancellationToken,
) -> Result<Vec<Attachment>, String> {
match File::open(input) {
Ok(input) => {
let reader = BufReader::new(&input);
let source = BinaryByteSource::new(reader);
let parser = DltParser::new(
filter.map(|f| f.into()),
None,
None,
None,
with_storage_header,
);

let mut producer = MessageProducer::new(parser, source);

let mut canceled = false;

let mut attachments = vec![];
loop {
tokio::select! {
// Check on events in current order ensuring cancel will be checked at first
// as it's defined in the current unit tests.
biased;
_ = cancel.cancelled() => {
debug!("scan canceled");
canceled = true;
let setup = SessionSetup {
origin: SessionAction::File(filename),
parser: parsers::dlt::descriptor::get_default_options(None, filters),
source: sources::binary::raw::get_default_options(),
};
let (session, receiver) = Session::new(Uuid::new_v4())
.await
.map_err(|err| err.to_string())?;
let (_, source, parser) = session
.register
.setup(&setup)
.map_err(|err| err.to_string())?;
let mut collector = AttachmentsCollector::default();
let mut producer = MessageProducer::new(parser, source, &mut collector);
let mut canceled = false;
loop {
tokio::select! {
// Check on events in current order ensuring cancel will be checked at first
// as it's defined in the current unit tests.
biased;
_ = cancel.cancelled() => {
debug!("scan canceled");
canceled = true;
break;
}
item = producer.read_next_segment() => {
match item {
Some((_, MessageStreamItem::Done)) | None => {
break;
}
items = producer.read_next_segment() => {
match items {
Some(items) => {
for (_, item) in items {
if let MessageStreamItem::Item(ParseYield::MessageAndAttachment((_msg, attachment))) = item {
attachments.push(attachment.to_owned());
} else if let MessageStreamItem::Item(ParseYield::Attachment(attachment)) = item {
attachments.push(attachment.to_owned());
}
}
}
_ => {
break;
}
}
}
},
Some(..) => {
continue;
},
}
}

if canceled {
return Ok(Vec::new());
}

Ok(attachments)
}
Err(error) => Err(format!("failed to open file: {error}")),
}
if canceled {
return Ok(Vec::new());
}
// Keep receiver alive until here
drop(receiver);
Ok(collector.attachments)
}

pub fn extract_dlt_ft(
Expand Down Expand Up @@ -126,14 +149,14 @@ mod tests {
use super::*;
use std::path::Path;

const DLT_FT_SAMPLE: &str = "../../../../../application/developing/resources/attachments.dlt";
const DLT_FT_SAMPLE: &str = "../../../../developing/resources/attachments.dlt";

#[tokio::test]
async fn test_scan_dlt_ft() {
let input: PathBuf = Path::new(DLT_FT_SAMPLE).into();

let cancel = CancellationToken::new();
match scan_dlt_ft(input, None, true, cancel).await {
match scan_dlt_ft(input, None, cancel).await {
Ok(files) => {
assert_eq!(files.len(), 3);
assert_eq!("test1.txt", files.first().unwrap().name);
Expand All @@ -153,7 +176,7 @@ mod tests {
let cancel = CancellationToken::new();
cancel.cancel();

match scan_dlt_ft(input, None, true, cancel).await {
match scan_dlt_ft(input, None, cancel).await {
Ok(files) => {
assert_eq!(files.len(), 0);
}
Expand All @@ -166,18 +189,10 @@ mod tests {
#[tokio::test]
async fn test_scan_dlt_ft_with_filter() {
let input: PathBuf = Path::new(DLT_FT_SAMPLE).into();

let filter = DltFilterConfig {
min_log_level: None,
app_ids: None,
ecu_ids: Some(vec!["ecu2".to_string()]),
context_ids: None,
app_id_count: 0,
context_id_count: 0,
};

let mut filters = HashMap::new();
filters.insert("ecu_ids".to_string(), vec!["ecu2".to_string()]);
let cancel = CancellationToken::new();
match scan_dlt_ft(input, Some(filter), true, cancel).await {
match scan_dlt_ft(input, Some(filters), cancel).await {
Ok(files) => {
assert_eq!(files.len(), 1);
assert_eq!("test2.txt", files.first().unwrap().name);
Expand All @@ -194,7 +209,7 @@ mod tests {
let output = TempDir::new();

let cancel = CancellationToken::new();
match scan_dlt_ft(input.clone(), None, true, cancel.clone()).await {
match scan_dlt_ft(input.clone(), None, cancel.clone()).await {
Ok(files) => {
match extract_dlt_ft(
&output.dir,
Expand Down Expand Up @@ -225,7 +240,7 @@ mod tests {
let output = TempDir::new();

let cancel = CancellationToken::new();
match scan_dlt_ft(input.clone(), None, true, cancel).await {
match scan_dlt_ft(input.clone(), None, cancel).await {
Ok(files) => {
let cancel = CancellationToken::new();
cancel.cancel();
Expand All @@ -248,18 +263,10 @@ mod tests {
async fn test_extract_dlt_ft_with_filter() {
let input: PathBuf = Path::new(DLT_FT_SAMPLE).into();
let output = TempDir::new();

let filter = DltFilterConfig {
min_log_level: None,
app_ids: None,
ecu_ids: Some(vec!["ecu2".to_string()]),
context_ids: None,
app_id_count: 0,
context_id_count: 0,
};

let mut filters = HashMap::new();
filters.insert("ecu_ids".to_string(), vec!["ecu2".to_string()]);
let cancel = CancellationToken::new();
match scan_dlt_ft(input.clone(), Some(filter), true, cancel).await {
match scan_dlt_ft(input.clone(), Some(filters), cancel).await {
Ok(files) => {
let cancel = CancellationToken::new();
match extract_dlt_ft(&output.dir, FileExtractor::files_with_names(files), cancel) {
Expand All @@ -285,7 +292,7 @@ mod tests {
let output = TempDir::new();

let cancel = CancellationToken::new();
match scan_dlt_ft(input.clone(), None, true, cancel).await {
match scan_dlt_ft(input.clone(), None, cancel).await {
Ok(files) => {
let cancel = CancellationToken::new();
match extract_dlt_ft(
Expand Down Expand Up @@ -313,18 +320,10 @@ mod tests {
async fn test_extract_dlt_ft_with_filtered_index() {
let input: PathBuf = Path::new(DLT_FT_SAMPLE).into();
let output = TempDir::new();

let filter = DltFilterConfig {
min_log_level: None,
app_ids: None,
ecu_ids: Some(vec!["ecu2".to_string()]),
context_ids: None,
app_id_count: 0,
context_id_count: 0,
};

let mut filters = HashMap::new();
filters.insert("ecu_ids".to_string(), vec!["ecu2".to_string()]);
let cancel = CancellationToken::new();
match scan_dlt_ft(input.clone(), Some(filter), true, cancel).await {
match scan_dlt_ft(input.clone(), Some(filters), cancel).await {
Ok(files) => {
let cancel = CancellationToken::new();
match extract_dlt_ft(&output.dir, FileExtractor::files_with_names(files), cancel) {
Expand Down
5 changes: 5 additions & 0 deletions application/apps/indexer/addons/file-tools/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ pub fn is_binary(file_path: String) -> Result<bool> {
Ok(from_utf8(&buffer).map_or(true, |_file_content| false))
}

pub fn is_path_binary<P: AsRef<Path>>(file_path: P) -> Result<bool> {
let buffer = fetch_starting_chunk(file_path.as_ref())?;
Ok(from_utf8(&buffer).map_or(true, |_file_content| false))
}

fn fetch_starting_chunk(file_path: &Path) -> Result<Vec<u8>> {
let bytes_to_read: u64 = (metadata(file_path)?.len().max(1) - 1).min(BYTES_TO_READ);

Expand Down
Loading