blob: 02b6b95d9dd4bf05cc6e9f98a2f18f60942ace3c [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
fidl_fuchsia_diagnostics::Selector,
lazy_static::lazy_static,
selectors::{self, FastError},
};
lazy_static! {
#[derive(Clone)]
static ref MONIKERS_TO_REWRITE: Vec<MonikerRewritePair> = vec![
// Note: These are unparsed strings, not separated into moniker segments.
// legacy_str cannot contain slashes but modern_str can.
MonikerRewritePair {
legacy_str: "memory_monitor.cmx",
modern_str: "core/memory_monitor",
},
MonikerRewritePair {
legacy_str: "wlanstack.cmx",
modern_str: "core/wlanstack",
},
MonikerRewritePair {
legacy_str: "omaha-client-service.cmx",
modern_str: "core/omaha-client-service",
},
MonikerRewritePair {
legacy_str: "cobalt_system_metrics.cmx",
modern_str: "core/cobalt_system_metrics"
}
];
}
pub struct MonikerRewriter {
monikers: Vec<MonikerRewritePair>,
}
#[derive(Clone, Debug)]
pub struct MonikerRewritePair {
legacy_str: &'static str,
modern_str: &'static str,
}
impl MonikerRewriter {
pub(crate) fn new() -> Self {
Self { monikers: MONIKERS_TO_REWRITE.to_vec() }
}
/// Checks whether any of the selectors needs rewriting. If so, it returns an OutputRewriter
/// that makes the corresponding change on the output. Otherwise, it returns None for the
/// rewriter. Either way, it returns the correct set of selectors.
pub(crate) fn rewrite_selectors(
&self,
mut selectors: Vec<Selector>,
) -> (Option<Vec<Selector>>, Option<OutputRewriter>) {
let mut monikers_rewritten = Vec::new();
for s in selectors.iter_mut() {
for pair in &self.monikers {
// Not expecting an error here, but if we get one, don't make any changes.
if selectors::match_component_moniker_against_selector(&[pair.legacy_str], s)
.unwrap_or(false)
{
if let Ok(selector) =
selectors::parse_component_selector::<FastError>(pair.modern_str)
{
s.component_selector = Some(selector);
monikers_rewritten.push(pair.clone());
}
}
}
}
let rewriter = if monikers_rewritten.is_empty() {
None
} else {
Some(OutputRewriter { monikers: monikers_rewritten })
};
(Some(selectors), rewriter)
}
}
#[derive(Debug)]
pub struct OutputRewriter {
monikers: Vec<MonikerRewritePair>,
}
impl OutputRewriter {
pub(crate) fn rewrite_moniker(&self, moniker: String) -> String {
for pair in &self.monikers {
if pair.modern_str == moniker {
return pair.legacy_str.to_string();
}
}
moniker
}
}
#[cfg(test)]
mod test {
use super::*;
use fidl_fuchsia_diagnostics::StringSelector;
use selectors::VerboseError;
macro_rules! extract_moniker {
($selector:expr) => {
extract_moniker!($selector, 0)
};
($selectors:expr, $index:expr) => {
$selectors.as_ref().unwrap()[$index]
.component_selector
.as_ref()
.unwrap()
.moniker_segments
.as_ref()
.unwrap()
};
}
#[fuchsia::test]
fn moniker_rewriter_works() {
let rewriter = MonikerRewriter::new();
let legacy_selector =
selectors::parse_selector::<VerboseError>("memory_monitor.cmx:path/to:data").unwrap();
let new_selector =
selectors::parse_selector::<VerboseError>("core/memory_monitor:path/to:data").unwrap();
let irrelevant_selector =
selectors::parse_selector::<VerboseError>("foo/bar.baz:path/to:data").unwrap();
let (rewritten_legacy, legacy_rewriter) = rewriter.rewrite_selectors(vec![legacy_selector]);
let (rewritten_new, new_rewriter) = rewriter.rewrite_selectors(vec![new_selector]);
let (rewritten_irrelevant, irrelevant_rewriter) =
rewriter.rewrite_selectors(vec![irrelevant_selector]);
assert_eq!(
extract_moniker!(rewritten_legacy),
&vec![
StringSelector::ExactMatch("core".to_string()),
StringSelector::ExactMatch("memory_monitor".to_string())
]
);
assert_eq!(
extract_moniker!(rewritten_new),
&vec![
StringSelector::ExactMatch("core".to_string()),
StringSelector::ExactMatch("memory_monitor".to_string())
]
);
assert_eq!(
extract_moniker!(rewritten_irrelevant),
&vec![
StringSelector::ExactMatch("foo".to_string()),
StringSelector::ExactMatch("bar.baz".to_string())
]
);
assert!(new_rewriter.is_none());
assert!(irrelevant_rewriter.is_none());
let rewriter = legacy_rewriter.unwrap();
assert_eq!(rewriter.rewrite_moniker("foo/bar.baz".to_string()), "foo/bar.baz".to_string());
assert_eq!(
rewriter.rewrite_moniker("memory_monitor.cmx".to_string()),
"memory_monitor.cmx".to_string()
);
assert_eq!(
rewriter.rewrite_moniker("core/memory_monitor".to_string()),
"memory_monitor.cmx".to_string()
);
}
#[fuchsia::test]
fn array_logic_works() {
let rewriter = MonikerRewriter {
monikers: vec![
MonikerRewritePair { legacy_str: "legacy1", modern_str: "modern1" },
MonikerRewritePair { legacy_str: "legacy2", modern_str: "modern2" },
],
};
let legacy_selector1 =
selectors::parse_selector::<VerboseError>("legacy1:path/to:data").unwrap();
let legacy_selector2 =
selectors::parse_selector::<VerboseError>("legacy2:path/to:data").unwrap();
let irrelevant_selector =
selectors::parse_selector::<VerboseError>("irrelevant:path/to:data").unwrap();
let (rewritten_1_i, rewriter_1_i) =
rewriter.rewrite_selectors(vec![legacy_selector1.clone(), irrelevant_selector.clone()]);
let (rewritten_2_1, rewriter_2_1) =
rewriter.rewrite_selectors(vec![legacy_selector2.clone(), legacy_selector1.clone()]);
let rewriter_1_i = rewriter_1_i.unwrap();
let rewriter_2_1 = rewriter_2_1.unwrap();
assert_eq!(
extract_moniker!(rewritten_1_i, 0),
&vec![StringSelector::ExactMatch("modern1".to_string()),]
);
assert_eq!(
extract_moniker!(rewritten_1_i, 1),
&vec![StringSelector::ExactMatch("irrelevant".to_string()),]
);
assert_eq!(
extract_moniker!(rewritten_2_1, 0),
&vec![StringSelector::ExactMatch("modern2".to_string()),]
);
assert_eq!(
extract_moniker!(rewritten_2_1, 1),
&vec![StringSelector::ExactMatch("modern1".to_string()),]
);
assert_eq!(rewriter_1_i.rewrite_moniker("modern1".to_string()), "legacy1".to_string());
assert_eq!(rewriter_1_i.rewrite_moniker("modern2".to_string()), "modern2".to_string());
assert_eq!(rewriter_2_1.rewrite_moniker("modern1".to_string()), "legacy1".to_string());
assert_eq!(rewriter_2_1.rewrite_moniker("modern2".to_string()), "legacy2".to_string());
}
}