Skip to content

Commit

Permalink
Merge pull request #807 from JomerDev/watch-elf-file
Browse files Browse the repository at this point in the history
Adds a watch flag to watch the elf file and reloads the file if it changed
  • Loading branch information
Urhengulas authored Sep 3, 2024
2 parents 987724b + 4f1095e commit b1b2c0f
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 19 deletions.
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,28 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- [#859]: `defmt`: Satisfy clippy
- [#858]: `defmt`: Implement "passthrough" trait impls for *2Format wrappers
- [#857]: Add an octal display hint (`:o`)
- [#856]: `defmt`: Add a `Format` impl for `PanicInfo` and related types.
- [#855]: `defmt-print`: Now uses tokio to make tcp and stdin reads async (in preparation for a `watch elf` flag)
- [#852]: `CI`: Update mdbook to v0.4.40
- [#848]: `decoder`: add optional one-line format
- [#847]: `decoder`: Fix log format width specifier not working as expected
- [#845]: `decoder`: fix println!() records being printed with formatting
- [#843]: `defmt`: Sort IDs of log msgs by severity to allow runtime filtering by severity
- [#822]: `CI`: Run `cargo semver-checks` on every PR
- [#856]: `defmt`: Add a `Format` impl for `PanicInfo` and related types.
- [#807]: `defmt-print`: Add `watch_elf` flag to allow ELF file reload without restarting `defmt-print`

[#859]: https://github.com/knurling-rs/defmt/pull/859
[#858]: https://github.com/knurling-rs/defmt/pull/858
[#857]: https://github.com/knurling-rs/defmt/pull/857
[#856]: https://github.com/knurling-rs/defmt/pull/856
[#855]: https://github.com/knurling-rs/defmt/pull/855
[#852]: https://github.com/knurling-rs/defmt/pull/852
[#848]: https://github.com/knurling-rs/defmt/pull/848
[#847]: https://github.com/knurling-rs/defmt/pull/847
[#845]: https://github.com/knurling-rs/defmt/pull/845
[#843]: https://github.com/knurling-rs/defmt/pull/843
[#822]: https://github.com/knurling-rs/defmt/pull/822
[#856]: https://github.com/knurling-rs/defmt/pull/856
[#807]: https://github.com/knurling-rs/defmt/pull/807

## [v0.3.8] - 2024-05-17

Expand Down
1 change: 1 addition & 0 deletions decoder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ object = { version = "0.35", default-features = false, features = [
serde = { version = "1", features = ["derive"] }
serde_json = { version = "1", features = ["arbitrary_precision"] }
regex = "1"
alterable_logger = "1"

[features]
# WARNING: API and wire format subject to change.
Expand Down
4 changes: 2 additions & 2 deletions decoder/src/log/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ pub fn init_logger(
JsonLogger::new(formatter, host_formatter, should_log)
}
};
log::set_boxed_logger(logger).unwrap();
log::set_max_level(LevelFilter::Trace);
alterable_logger::set_boxed_logger(logger);
alterable_logger::set_max_level(LevelFilter::Trace);
}

fn timestamp_and_level_from_frame(frame: &Frame<'_>) -> (String, Option<Level>) {
Expand Down
1 change: 1 addition & 0 deletions print/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ defmt-decoder = { version = "=0.3.11", path = "../decoder", features = [
"unstable",
] }
log = "0.4"
notify = "6.1"
tokio = { version = "1.38", features = ["full"] }
83 changes: 68 additions & 15 deletions print/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ use defmt_decoder::{
},
DecodeError, Frame, Locations, Table, DEFMT_VERSIONS,
};

use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Watcher};
use tokio::{
fs,
io::{self, AsyncReadExt, Stdin},
net::TcpStream,
select,
sync::mpsc::Receiver,
};

/// Prints defmt-encoded logs to stdout
#[derive(Parser)]
#[derive(Parser, Clone)]
#[command(name = "defmt-print")]
struct Opts {
#[arg(short, required = true, conflicts_with("version"))]
Expand All @@ -44,11 +46,14 @@ struct Opts {
#[arg(short = 'V', long)]
version: bool,

#[arg(short, long)]
watch_elf: bool,

#[command(subcommand)]
command: Option<Command>,
}

#[derive(Subcommand)]
#[derive(Subcommand, Clone)]
enum Command {
/// Read defmt frames from stdin (default)
Stdin,
Expand Down Expand Up @@ -94,20 +99,73 @@ const READ_BUFFER_SIZE: usize = 1024;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let opts = Opts::parse();

if opts.version {
return print_version();
}

// We create the source outside of the run command since recreating the stdin looses us some frames
let mut source = match opts.command.clone() {
None | Some(Command::Stdin) => Source::stdin(),
Some(Command::Tcp { host, port }) => Source::tcp(host, port).await?,
};

if opts.watch_elf {
run_and_watch(opts, &mut source).await
} else {
run(opts, &mut source).await
}
}

async fn has_file_changed(rx: &mut Receiver<Result<Event, notify::Error>>, path: &PathBuf) -> bool {
loop {
if let Some(Ok(event)) = rx.recv().await {
if event.paths.contains(path) {
if let notify::EventKind::Create(_) | notify::EventKind::Modify(_) = event.kind {
break;
}
}
}
}
true
}

async fn run_and_watch(opts: Opts, source: &mut Source) -> anyhow::Result<()> {
let (tx, mut rx) = tokio::sync::mpsc::channel(1);

let path = opts.elf.clone().unwrap().canonicalize().unwrap();

// We want the elf directory instead of the elf, since some editors remove
// and recreate the file on save which will remove the notifier
let directory_path = path.parent().unwrap();

let mut watcher = RecommendedWatcher::new(
move |res| {
let _ = tx.blocking_send(res);
},
Config::default(),
)?;
watcher.watch(directory_path.as_ref(), RecursiveMode::NonRecursive)?;

loop {
select! {
r = run(opts.clone(), source) => r?,
_ = has_file_changed(&mut rx, &path) => ()
}
}
}

async fn run(opts: Opts, source: &mut Source) -> anyhow::Result<()> {
let Opts {
elf,
json,
log_format,
host_log_format,
show_skipped_frames,
verbose,
version,
command,
} = Opts::parse();

if version {
return print_version();
}
..
} = opts;

// read and parse elf file
let bytes = fs::read(elf.unwrap()).await?;
Expand Down Expand Up @@ -162,11 +220,6 @@ async fn main() -> anyhow::Result<()> {
let mut stream_decoder = table.new_stream_decoder();
let current_dir = env::current_dir()?;

let mut source = match command {
None | Some(Command::Stdin) => Source::stdin(),
Some(Command::Tcp { host, port }) => Source::tcp(host, port).await?,
};

loop {
// read from stdin or tcpstream and push it to the decoder
let (n, eof) = source.read(&mut buf).await?;
Expand Down

0 comments on commit b1b2c0f

Please sign in to comment.