mirror of https://github.com/msfjarvis/adx.git
adx: undo custom formatting
This commit is contained in:
parent
79c2a49834
commit
dafee9a48b
|
@ -12,151 +12,149 @@ use thiserror::Error;
|
|||
/// order.
|
||||
#[derive(Debug, Eq, PartialEq, PartialOrd, Clone, Copy)]
|
||||
pub(crate) enum Channel {
|
||||
Dev,
|
||||
Alpha,
|
||||
Beta,
|
||||
Rc,
|
||||
Stable,
|
||||
Dev,
|
||||
Alpha,
|
||||
Beta,
|
||||
Rc,
|
||||
Stable,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub(crate) enum ChannelError {
|
||||
#[error("no match found")]
|
||||
NoMatchFound,
|
||||
#[error("failed to determine channel for {0}")]
|
||||
FailedToParseVersion(Version),
|
||||
#[error("no match found")]
|
||||
NoMatchFound,
|
||||
#[error("failed to determine channel for {0}")]
|
||||
FailedToParseVersion(Version),
|
||||
}
|
||||
|
||||
impl FromStr for Channel {
|
||||
type Err = ChannelError;
|
||||
type Err = ChannelError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"alpha" | "a" => Ok(Channel::Alpha),
|
||||
"beta" | "b" => Ok(Channel::Beta),
|
||||
"dev" | "d" => Ok(Channel::Dev),
|
||||
"rc" | "r" => Ok(Channel::Rc),
|
||||
"stable" | "s" => Ok(Channel::Stable),
|
||||
_ => Err(ChannelError::NoMatchFound),
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"alpha" | "a" => Ok(Channel::Alpha),
|
||||
"beta" | "b" => Ok(Channel::Beta),
|
||||
"dev" | "d" => Ok(Channel::Dev),
|
||||
"rc" | "r" => Ok(Channel::Rc),
|
||||
"stable" | "s" => Ok(Channel::Stable),
|
||||
_ => Err(ChannelError::NoMatchFound),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Version> for Channel {
|
||||
type Error = ChannelError;
|
||||
type Error = ChannelError;
|
||||
|
||||
fn try_from(value: Version) -> Result<Self, Self::Error> {
|
||||
if value.pre == Prerelease::EMPTY {
|
||||
Ok(Channel::Stable)
|
||||
} else {
|
||||
let pre_str = value.pre.to_string();
|
||||
if pre_str.starts_with("alpha") {
|
||||
Ok(Channel::Alpha)
|
||||
} else if pre_str.starts_with("beta") {
|
||||
Ok(Channel::Beta)
|
||||
} else if pre_str.starts_with("dev") {
|
||||
Ok(Channel::Dev)
|
||||
} else if pre_str.starts_with("rc") {
|
||||
Ok(Channel::Rc)
|
||||
} else {
|
||||
Err(ChannelError::FailedToParseVersion(value))
|
||||
}
|
||||
fn try_from(value: Version) -> Result<Self, Self::Error> {
|
||||
if value.pre == Prerelease::EMPTY {
|
||||
Ok(Channel::Stable)
|
||||
} else {
|
||||
let pre_str = value.pre.to_string();
|
||||
if pre_str.starts_with("alpha") {
|
||||
Ok(Channel::Alpha)
|
||||
} else if pre_str.starts_with("beta") {
|
||||
Ok(Channel::Beta)
|
||||
} else if pre_str.starts_with("dev") {
|
||||
Ok(Channel::Dev)
|
||||
} else if pre_str.starts_with("rc") {
|
||||
Ok(Channel::Rc)
|
||||
} else {
|
||||
Err(ChannelError::FailedToParseVersion(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use semver::{BuildMetadata, Prerelease, Version};
|
||||
use semver::{BuildMetadata, Prerelease, Version};
|
||||
|
||||
use super::Channel;
|
||||
use super::Channel;
|
||||
|
||||
#[test]
|
||||
fn alpha_version() {
|
||||
let v = Version {
|
||||
major: 1,
|
||||
minor: 1,
|
||||
patch: 0,
|
||||
pre: Prerelease::new("alpha01").unwrap(),
|
||||
build: BuildMetadata::EMPTY,
|
||||
};
|
||||
let channel = Channel::try_from(v);
|
||||
assert_eq!(Channel::Alpha, channel.unwrap());
|
||||
}
|
||||
#[test]
|
||||
fn alpha_version() {
|
||||
let v = Version {
|
||||
major: 1,
|
||||
minor: 1,
|
||||
patch: 0,
|
||||
pre: Prerelease::new("alpha01").unwrap(),
|
||||
build: BuildMetadata::EMPTY,
|
||||
};
|
||||
let channel = Channel::try_from(v);
|
||||
assert_eq!(Channel::Alpha, channel.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn beta_version() {
|
||||
let v = Version {
|
||||
major: 1,
|
||||
minor: 1,
|
||||
patch: 0,
|
||||
pre: Prerelease::new("beta01").unwrap(),
|
||||
build: BuildMetadata::EMPTY,
|
||||
};
|
||||
let channel = Channel::try_from(v);
|
||||
assert_eq!(Channel::Beta, channel.unwrap());
|
||||
}
|
||||
#[test]
|
||||
fn beta_version() {
|
||||
let v = Version {
|
||||
major: 1,
|
||||
minor: 1,
|
||||
patch: 0,
|
||||
pre: Prerelease::new("beta01").unwrap(),
|
||||
build: BuildMetadata::EMPTY,
|
||||
};
|
||||
let channel = Channel::try_from(v);
|
||||
assert_eq!(Channel::Beta, channel.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dev_version() {
|
||||
let v = Version {
|
||||
major: 1,
|
||||
minor: 1,
|
||||
patch: 0,
|
||||
pre: Prerelease::new("dev01").unwrap(),
|
||||
build: BuildMetadata::EMPTY,
|
||||
};
|
||||
let channel = Channel::try_from(v);
|
||||
assert_eq!(Channel::Dev, channel.unwrap());
|
||||
}
|
||||
#[test]
|
||||
fn dev_version() {
|
||||
let v = Version {
|
||||
major: 1,
|
||||
minor: 1,
|
||||
patch: 0,
|
||||
pre: Prerelease::new("dev01").unwrap(),
|
||||
build: BuildMetadata::EMPTY,
|
||||
};
|
||||
let channel = Channel::try_from(v);
|
||||
assert_eq!(Channel::Dev, channel.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rc_version() {
|
||||
let v = Version {
|
||||
major: 1,
|
||||
minor: 1,
|
||||
patch: 0,
|
||||
pre: Prerelease::new("rc01").unwrap(),
|
||||
build: BuildMetadata::EMPTY,
|
||||
};
|
||||
let channel = Channel::try_from(v);
|
||||
assert_eq!(Channel::Rc, channel.unwrap());
|
||||
}
|
||||
#[test]
|
||||
fn rc_version() {
|
||||
let v = Version {
|
||||
major: 1,
|
||||
minor: 1,
|
||||
patch: 0,
|
||||
pre: Prerelease::new("rc01").unwrap(),
|
||||
build: BuildMetadata::EMPTY,
|
||||
};
|
||||
let channel = Channel::try_from(v);
|
||||
assert_eq!(Channel::Rc, channel.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stable_version() {
|
||||
let v = Version::new(1, 1, 1);
|
||||
let channel = Channel::try_from(v);
|
||||
assert_eq!(Channel::Stable, channel.unwrap());
|
||||
}
|
||||
#[test]
|
||||
fn stable_version() {
|
||||
let v = Version::new(1, 1, 1);
|
||||
let channel = Channel::try_from(v);
|
||||
assert_eq!(Channel::Stable, channel.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmp_channels() {
|
||||
assert!(Channel::Stable > Channel::Rc);
|
||||
assert!(Channel::Rc > Channel::Beta);
|
||||
assert!(Channel::Beta > Channel::Alpha);
|
||||
assert!(Channel::Alpha > Channel::Dev);
|
||||
}
|
||||
#[test]
|
||||
fn cmp_channels() {
|
||||
assert!(Channel::Stable > Channel::Rc);
|
||||
assert!(Channel::Rc > Channel::Beta);
|
||||
assert!(Channel::Beta > Channel::Alpha);
|
||||
assert!(Channel::Alpha > Channel::Dev);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmp_parsed_versions() {
|
||||
let stable = Channel::try_from(Version::parse("1.1.0").unwrap()).unwrap();
|
||||
let rc = Channel::try_from(Version::parse("1.1.0-rc01").unwrap()).unwrap();
|
||||
let alpha =
|
||||
Channel::try_from(Version::parse("1.1.0-alpha01").unwrap()).unwrap();
|
||||
let beta =
|
||||
Channel::try_from(Version::parse("1.1.0-beta01").unwrap()).unwrap();
|
||||
assert!(Channel::Stable >= stable);
|
||||
assert!(Channel::Stable >= rc);
|
||||
assert!(Channel::Stable >= alpha);
|
||||
assert!(Channel::Stable >= beta);
|
||||
assert!(Channel::Rc >= rc);
|
||||
assert!(Channel::Rc >= beta);
|
||||
assert!(Channel::Rc >= alpha);
|
||||
assert!(Channel::Beta >= beta);
|
||||
assert!(Channel::Beta >= alpha);
|
||||
assert!(Channel::Alpha >= alpha);
|
||||
}
|
||||
#[test]
|
||||
fn cmp_parsed_versions() {
|
||||
let stable = Channel::try_from(Version::parse("1.1.0").unwrap()).unwrap();
|
||||
let rc = Channel::try_from(Version::parse("1.1.0-rc01").unwrap()).unwrap();
|
||||
let alpha = Channel::try_from(Version::parse("1.1.0-alpha01").unwrap()).unwrap();
|
||||
let beta = Channel::try_from(Version::parse("1.1.0-beta01").unwrap()).unwrap();
|
||||
assert!(Channel::Stable >= stable);
|
||||
assert!(Channel::Stable >= rc);
|
||||
assert!(Channel::Stable >= alpha);
|
||||
assert!(Channel::Stable >= beta);
|
||||
assert!(Channel::Rc >= rc);
|
||||
assert!(Channel::Rc >= beta);
|
||||
assert!(Channel::Rc >= alpha);
|
||||
assert!(Channel::Beta >= beta);
|
||||
assert!(Channel::Beta >= alpha);
|
||||
assert!(Channel::Alpha >= alpha);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,33 +21,33 @@ static GLOBAL: &StatsAlloc<System> = &INSTRUMENTED_SYSTEM;
|
|||
#[clap(author, version, about)]
|
||||
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
|
||||
pub(crate) struct Cli {
|
||||
/// search term to filter packages with
|
||||
#[cfg(not(feature = "measure-alloc"))]
|
||||
#[clap(required = true)]
|
||||
pub(crate) search_term: String,
|
||||
/// the release channel to find packages from
|
||||
#[clap(short='c', long="channel", possible_values=&["alpha", "a", "beta", "b", "dev", "d", "rc", "r", "stable", "s"], default_value="a")]
|
||||
pub(crate) channel: Channel,
|
||||
/// search term to filter packages with
|
||||
#[cfg(not(feature = "measure-alloc"))]
|
||||
#[clap(required = true)]
|
||||
pub(crate) search_term: String,
|
||||
/// the release channel to find packages from
|
||||
#[clap(short='c', long="channel", possible_values=&["alpha", "a", "beta", "b", "dev", "d", "rc", "r", "stable", "s"], default_value="a")]
|
||||
pub(crate) channel: Channel,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
#[cfg(feature = "measure-alloc")]
|
||||
let reg = Region::new(GLOBAL);
|
||||
let cli = Cli::parse();
|
||||
#[cfg(feature = "measure-alloc")]
|
||||
let packages = crate::parse::parse("", cli.channel).await?;
|
||||
#[cfg(not(feature = "measure-alloc"))]
|
||||
let packages = crate::parse::parse(&cli.search_term, cli.channel).await?;
|
||||
if packages.is_empty() {
|
||||
println!("No results found!");
|
||||
} else {
|
||||
for package in &packages {
|
||||
println!("{}", package);
|
||||
}
|
||||
};
|
||||
#[cfg(feature = "measure-alloc")]
|
||||
println!("{:#?}", reg.change());
|
||||
Ok(())
|
||||
color_eyre::install()?;
|
||||
#[cfg(feature = "measure-alloc")]
|
||||
let reg = Region::new(GLOBAL);
|
||||
let cli = Cli::parse();
|
||||
#[cfg(feature = "measure-alloc")]
|
||||
let packages = crate::parse::parse("", cli.channel).await?;
|
||||
#[cfg(not(feature = "measure-alloc"))]
|
||||
let packages = crate::parse::parse(&cli.search_term, cli.channel).await?;
|
||||
if packages.is_empty() {
|
||||
println!("No results found!");
|
||||
} else {
|
||||
for package in &packages {
|
||||
println!("{}", package);
|
||||
}
|
||||
};
|
||||
#[cfg(feature = "measure-alloc")]
|
||||
println!("{:#?}", reg.change());
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -3,17 +3,17 @@ use std::fmt::{Debug, Display, Formatter, Result};
|
|||
/// Struct that represents a Maven package
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct MavenPackage {
|
||||
pub(crate) group_id: String,
|
||||
pub(crate) artifact_id: String,
|
||||
pub(crate) latest_version: String,
|
||||
pub(crate) group_id: String,
|
||||
pub(crate) artifact_id: String,
|
||||
pub(crate) latest_version: String,
|
||||
}
|
||||
|
||||
impl Display for MavenPackage {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
write!(
|
||||
f,
|
||||
"{}:{}:{}",
|
||||
self.group_id, self.artifact_id, self.latest_version,
|
||||
)
|
||||
}
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
write!(
|
||||
f,
|
||||
"{}:{}:{}",
|
||||
self.group_id, self.artifact_id, self.latest_version,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
243
adx/src/parse.rs
243
adx/src/parse.rs
|
@ -16,7 +16,27 @@ const BASE_MAVEN_URL: &str = "https://dl.google.com/dl/android/maven2";
|
|||
/// and returns the XML as a String
|
||||
#[cfg(not(test))]
|
||||
async fn get_maven_index() -> Result<String> {
|
||||
reqwest::get(format!("{}/master-index.xml", BASE_MAVEN_URL))
|
||||
reqwest::get(format!("{}/master-index.xml", BASE_MAVEN_URL))
|
||||
.await?
|
||||
.text()
|
||||
.await
|
||||
.map_err(|e| eyre!(e))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unused_async)]
|
||||
async fn get_maven_index() -> Result<String> {
|
||||
std::fs::read_to_string("../testdata/master-index.xml").map_err(|e| eyre!(e))
|
||||
}
|
||||
|
||||
/// Downloads the group index for the given group.
|
||||
#[cfg(not(test))]
|
||||
async fn get_group_index(group: &str) -> Result<String> {
|
||||
reqwest::get(format!(
|
||||
"{}/{}/group-index.xml",
|
||||
BASE_MAVEN_URL,
|
||||
group.replace('.', "/")
|
||||
))
|
||||
.await?
|
||||
.text()
|
||||
.await
|
||||
|
@ -25,158 +45,123 @@ async fn get_maven_index() -> Result<String> {
|
|||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unused_async)]
|
||||
async fn get_maven_index() -> Result<String> {
|
||||
std::fs::read_to_string("../testdata/master-index.xml").map_err(|e| eyre!(e))
|
||||
}
|
||||
|
||||
/// Downloads the group index for the given group.
|
||||
#[cfg(not(test))]
|
||||
async fn get_group_index(group: &str) -> Result<String> {
|
||||
reqwest::get(format!(
|
||||
"{}/{}/group-index.xml",
|
||||
BASE_MAVEN_URL,
|
||||
group.replace('.', "/")
|
||||
))
|
||||
.await?
|
||||
.text()
|
||||
.await
|
||||
.map_err(|e| eyre!(e))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unused_async)]
|
||||
async fn get_group_index(group: &str) -> Result<String> {
|
||||
std::fs::read_to_string(format!("../testdata/{}.xml", group))
|
||||
.map_err(|e| eyre!(e))
|
||||
std::fs::read_to_string(format!("../testdata/{}.xml", group)).map_err(|e| eyre!(e))
|
||||
}
|
||||
|
||||
/// Parses a given master-index.xml and filters the found packages based on
|
||||
// `search_term`.
|
||||
fn filter_groups(doc: &Document<'_>, search_term: &str) -> Vec<String> {
|
||||
let mut groups = vec![];
|
||||
for node in doc
|
||||
.descendants()
|
||||
// Only keep elements
|
||||
.filter(|node| node.node_type() == NodeType::Element)
|
||||
// Skip the first one since it is junk
|
||||
.skip(1)
|
||||
{
|
||||
let tag = node.tag_name().name();
|
||||
if tag.contains(search_term) {
|
||||
groups.push(tag.to_string());
|
||||
let mut groups = vec![];
|
||||
for node in doc
|
||||
.descendants()
|
||||
// Only keep elements
|
||||
.filter(|node| node.node_type() == NodeType::Element)
|
||||
// Skip the first one since it is junk
|
||||
.skip(1)
|
||||
{
|
||||
let tag = node.tag_name().name();
|
||||
if tag.contains(search_term) {
|
||||
groups.push(tag.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
groups
|
||||
groups
|
||||
}
|
||||
|
||||
/// Given a list of groups, returns a `Vec<MavenPackage>` of all artifacts.
|
||||
async fn parse_packages(
|
||||
groups: Vec<String>,
|
||||
channel: Channel,
|
||||
) -> Result<Vec<MavenPackage>> {
|
||||
// Create a Vec<Future<_>>, this will allow us to run all tasks together
|
||||
// without requiring us to spawn a new thread
|
||||
let group_futures = groups
|
||||
.iter()
|
||||
.map(|group_name| parse_group(group_name, channel));
|
||||
async fn parse_packages(groups: Vec<String>, channel: Channel) -> Result<Vec<MavenPackage>> {
|
||||
// Create a Vec<Future<_>>, this will allow us to run all tasks together
|
||||
// without requiring us to spawn a new thread
|
||||
let group_futures = groups
|
||||
.iter()
|
||||
.map(|group_name| parse_group(group_name, channel));
|
||||
|
||||
// Wait for all groups to complete to get a Vec<Vec<MavenPackage>>
|
||||
let merged_list = join_all(group_futures).await;
|
||||
// Wait for all groups to complete to get a Vec<Vec<MavenPackage>>
|
||||
let merged_list = join_all(group_futures).await;
|
||||
|
||||
Ok(
|
||||
merged_list
|
||||
.into_iter()
|
||||
.filter_map(std::result::Result::ok)
|
||||
.flatten()
|
||||
.collect(),
|
||||
)
|
||||
Ok(merged_list
|
||||
.into_iter()
|
||||
.filter_map(std::result::Result::ok)
|
||||
.flatten()
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// Given a group, returns a `Vec<MavenPackage>` of all artifacts from this
|
||||
/// group.
|
||||
async fn parse_group(
|
||||
group_name: &str,
|
||||
channel: Channel,
|
||||
) -> Result<Vec<MavenPackage>> {
|
||||
let group_index = get_group_index(group_name).await?;
|
||||
let doc = Document::parse(&group_index)
|
||||
.map_err(|e| eyre!(e).with_note(|| format!("group_name={}", group_name)))?;
|
||||
Ok(
|
||||
doc
|
||||
.descendants()
|
||||
.filter(|node| node.node_type() == NodeType::Element)
|
||||
.filter(|node| node.tag_name().name() == group_name)
|
||||
.flat_map(|node| {
|
||||
node
|
||||
.children()
|
||||
.filter(|node| node.node_type() == NodeType::Element)
|
||||
.filter_map(|node| {
|
||||
let mut versions = node
|
||||
.attribute("versions")
|
||||
.unwrap()
|
||||
.split(',')
|
||||
.filter_map(|v| Version::parse(v).ok())
|
||||
.filter(|v| {
|
||||
if let Ok(c) = Channel::try_from(v.clone()) {
|
||||
c >= channel
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.collect::<Vec<Version>>();
|
||||
if versions.is_empty() {
|
||||
None
|
||||
} else {
|
||||
versions.sort_by(|a, b| b.partial_cmp(a).unwrap());
|
||||
Some(MavenPackage {
|
||||
group_id: String::from(group_name),
|
||||
artifact_id: node.tag_name().name().to_string(),
|
||||
latest_version: versions.get(0).unwrap().to_string(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.collect::<Vec<MavenPackage>>()
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
async fn parse_group(group_name: &str, channel: Channel) -> Result<Vec<MavenPackage>> {
|
||||
let group_index = get_group_index(group_name).await?;
|
||||
let doc = Document::parse(&group_index)
|
||||
.map_err(|e| eyre!(e).with_note(|| format!("group_name={}", group_name)))?;
|
||||
Ok(doc
|
||||
.descendants()
|
||||
.filter(|node| node.node_type() == NodeType::Element)
|
||||
.filter(|node| node.tag_name().name() == group_name)
|
||||
.flat_map(|node| {
|
||||
node.children()
|
||||
.filter(|node| node.node_type() == NodeType::Element)
|
||||
.filter_map(|node| {
|
||||
let mut versions = node
|
||||
.attribute("versions")
|
||||
.unwrap()
|
||||
.split(',')
|
||||
.filter_map(|v| Version::parse(v).ok())
|
||||
.filter(|v| {
|
||||
if let Ok(c) = Channel::try_from(v.clone()) {
|
||||
c >= channel
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.collect::<Vec<Version>>();
|
||||
if versions.is_empty() {
|
||||
None
|
||||
} else {
|
||||
versions.sort_by(|a, b| b.partial_cmp(a).unwrap());
|
||||
Some(MavenPackage {
|
||||
group_id: String::from(group_name),
|
||||
artifact_id: node.tag_name().name().to_string(),
|
||||
latest_version: versions.get(0).unwrap().to_string(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.collect::<Vec<MavenPackage>>()
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub(crate) async fn parse(
|
||||
search_term: &str,
|
||||
channel: Channel,
|
||||
) -> Result<Vec<MavenPackage>> {
|
||||
let maven_index = get_maven_index().await?;
|
||||
let doc = Document::parse(&maven_index)?;
|
||||
let groups = filter_groups(&doc, search_term);
|
||||
parse_packages(groups, channel).await
|
||||
pub(crate) async fn parse(search_term: &str, channel: Channel) -> Result<Vec<MavenPackage>> {
|
||||
let maven_index = get_maven_index().await?;
|
||||
let doc = Document::parse(&maven_index)?;
|
||||
let groups = filter_groups(&doc, search_term);
|
||||
parse_packages(groups, channel).await
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use color_eyre::eyre::eyre;
|
||||
use futures::executor::block_on;
|
||||
use color_eyre::eyre::eyre;
|
||||
use futures::executor::block_on;
|
||||
|
||||
use super::{parse, Channel};
|
||||
use super::{parse, Channel};
|
||||
|
||||
#[test]
|
||||
fn check_filter_works() {
|
||||
let res = block_on(parse("appcompat", Channel::Alpha))
|
||||
.map_err(|e| eyre!(e))
|
||||
.unwrap();
|
||||
assert_eq!(res.len(), 2);
|
||||
for pkg in &res {
|
||||
assert_eq!(pkg.group_id, "androidx.appcompat");
|
||||
#[test]
|
||||
fn check_filter_works() {
|
||||
let res = block_on(parse("appcompat", Channel::Alpha))
|
||||
.map_err(|e| eyre!(e))
|
||||
.unwrap();
|
||||
assert_eq!(res.len(), 2);
|
||||
for pkg in &res {
|
||||
assert_eq!(pkg.group_id, "androidx.appcompat");
|
||||
}
|
||||
assert!(res.iter().any(|pkg| pkg.artifact_id == "appcompat"));
|
||||
assert!(res
|
||||
.iter()
|
||||
.any(|pkg| pkg.artifact_id == "appcompat-resources"));
|
||||
}
|
||||
assert!(res.iter().any(|pkg| pkg.artifact_id == "appcompat"));
|
||||
assert!(res
|
||||
.iter()
|
||||
.any(|pkg| pkg.artifact_id == "appcompat-resources"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_all_packages_are_parsed() {
|
||||
let res = block_on(parse("", Channel::Stable))
|
||||
.expect("Parsing offline copies should always work");
|
||||
assert_eq!(res.len(), 754);
|
||||
}
|
||||
#[test]
|
||||
fn check_all_packages_are_parsed() {
|
||||
let res = block_on(parse("", Channel::Stable))
|
||||
.expect("Parsing offline copies should always work");
|
||||
assert_eq!(res.len(), 754);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,14 +26,14 @@
|
|||
//! ```
|
||||
|
||||
#![deny(
|
||||
missing_debug_implementations,
|
||||
missing_copy_implementations,
|
||||
trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
unused_import_braces,
|
||||
unused_imports,
|
||||
unused_qualifications,
|
||||
missing_docs
|
||||
missing_debug_implementations,
|
||||
missing_copy_implementations,
|
||||
trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
unused_import_braces,
|
||||
unused_imports,
|
||||
unused_qualifications,
|
||||
missing_docs
|
||||
)]
|
||||
#![allow(dead_code, unsafe_code)]
|
||||
#![cfg_attr(feature = "nightly", feature(const_fn))]
|
||||
|
@ -48,261 +48,247 @@ use std::sync::atomic::{AtomicIsize, AtomicUsize, Ordering};
|
|||
/// and reallocation requests to the underlying global allocator.
|
||||
#[derive(Default, Debug)]
|
||||
pub struct StatsAlloc<T: GlobalAlloc> {
|
||||
allocations: AtomicUsize,
|
||||
deallocations: AtomicUsize,
|
||||
reallocations: AtomicUsize,
|
||||
bytes_allocated: AtomicUsize,
|
||||
bytes_deallocated: AtomicUsize,
|
||||
bytes_reallocated: AtomicIsize,
|
||||
inner: T,
|
||||
allocations: AtomicUsize,
|
||||
deallocations: AtomicUsize,
|
||||
reallocations: AtomicUsize,
|
||||
bytes_allocated: AtomicUsize,
|
||||
bytes_deallocated: AtomicUsize,
|
||||
bytes_reallocated: AtomicIsize,
|
||||
inner: T,
|
||||
}
|
||||
|
||||
/// Allocator statistics
|
||||
#[derive(Clone, Copy, Default, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct Stats {
|
||||
/// Count of allocation operations
|
||||
pub allocations: usize,
|
||||
/// Count of deallocation operations
|
||||
pub deallocations: usize,
|
||||
/// Count of reallocation operations
|
||||
///
|
||||
/// An example where reallocation may occur: resizing of a `Vec<T>` when
|
||||
/// its length would excceed its capacity. Excessive reallocations may
|
||||
/// indicate that resizable data structures are being created with
|
||||
/// insufficient or poorly estimated initial capcities.
|
||||
///
|
||||
/// ```
|
||||
/// let mut x = Vec::with_capacity(1);
|
||||
/// x.push(0);
|
||||
/// x.push(1); // Potential reallocation
|
||||
/// ```
|
||||
pub reallocations: usize,
|
||||
/// Total bytes requested by allocations
|
||||
pub bytes_allocated: usize,
|
||||
/// Total bytes freed by deallocations
|
||||
pub bytes_deallocated: usize,
|
||||
/// Total of bytes requested minus bytes freed by reallocations
|
||||
///
|
||||
/// This number is positive if the total bytes requested by reallocation
|
||||
/// operations is greater than the total bytes freed by reallocations. A
|
||||
/// positive value indicates that resizable structures are growing, while
|
||||
/// a negative value indicates that such structures are shrinking.
|
||||
pub bytes_reallocated: isize,
|
||||
/// Count of allocation operations
|
||||
pub allocations: usize,
|
||||
/// Count of deallocation operations
|
||||
pub deallocations: usize,
|
||||
/// Count of reallocation operations
|
||||
///
|
||||
/// An example where reallocation may occur: resizing of a `Vec<T>` when
|
||||
/// its length would excceed its capacity. Excessive reallocations may
|
||||
/// indicate that resizable data structures are being created with
|
||||
/// insufficient or poorly estimated initial capcities.
|
||||
///
|
||||
/// ```
|
||||
/// let mut x = Vec::with_capacity(1);
|
||||
/// x.push(0);
|
||||
/// x.push(1); // Potential reallocation
|
||||
/// ```
|
||||
pub reallocations: usize,
|
||||
/// Total bytes requested by allocations
|
||||
pub bytes_allocated: usize,
|
||||
/// Total bytes freed by deallocations
|
||||
pub bytes_deallocated: usize,
|
||||
/// Total of bytes requested minus bytes freed by reallocations
|
||||
///
|
||||
/// This number is positive if the total bytes requested by reallocation
|
||||
/// operations is greater than the total bytes freed by reallocations. A
|
||||
/// positive value indicates that resizable structures are growing, while
|
||||
/// a negative value indicates that such structures are shrinking.
|
||||
pub bytes_reallocated: isize,
|
||||
}
|
||||
|
||||
/// An instrumented instance of the system allocator.
|
||||
pub static INSTRUMENTED_SYSTEM: StatsAlloc<System> = StatsAlloc {
|
||||
allocations: AtomicUsize::new(0),
|
||||
deallocations: AtomicUsize::new(0),
|
||||
reallocations: AtomicUsize::new(0),
|
||||
bytes_allocated: AtomicUsize::new(0),
|
||||
bytes_deallocated: AtomicUsize::new(0),
|
||||
bytes_reallocated: AtomicIsize::new(0),
|
||||
inner: System,
|
||||
allocations: AtomicUsize::new(0),
|
||||
deallocations: AtomicUsize::new(0),
|
||||
reallocations: AtomicUsize::new(0),
|
||||
bytes_allocated: AtomicUsize::new(0),
|
||||
bytes_deallocated: AtomicUsize::new(0),
|
||||
bytes_reallocated: AtomicIsize::new(0),
|
||||
inner: System,
|
||||
};
|
||||
|
||||
impl StatsAlloc<System> {
|
||||
/// Provides access to an instrumented instance of the system allocator.
|
||||
pub const fn system() -> Self {
|
||||
StatsAlloc {
|
||||
allocations: AtomicUsize::new(0),
|
||||
deallocations: AtomicUsize::new(0),
|
||||
reallocations: AtomicUsize::new(0),
|
||||
bytes_allocated: AtomicUsize::new(0),
|
||||
bytes_deallocated: AtomicUsize::new(0),
|
||||
bytes_reallocated: AtomicIsize::new(0),
|
||||
inner: System,
|
||||
/// Provides access to an instrumented instance of the system allocator.
|
||||
pub const fn system() -> Self {
|
||||
StatsAlloc {
|
||||
allocations: AtomicUsize::new(0),
|
||||
deallocations: AtomicUsize::new(0),
|
||||
reallocations: AtomicUsize::new(0),
|
||||
bytes_allocated: AtomicUsize::new(0),
|
||||
bytes_deallocated: AtomicUsize::new(0),
|
||||
bytes_reallocated: AtomicIsize::new(0),
|
||||
inner: System,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: GlobalAlloc> StatsAlloc<T> {
|
||||
/// Provides access to an instrumented instance of the given global
|
||||
/// allocator.
|
||||
#[cfg(feature = "nightly")]
|
||||
pub const fn new(inner: T) -> Self {
|
||||
StatsAlloc {
|
||||
allocations: AtomicUsize::new(0),
|
||||
deallocations: AtomicUsize::new(0),
|
||||
reallocations: AtomicUsize::new(0),
|
||||
bytes_allocated: AtomicUsize::new(0),
|
||||
bytes_deallocated: AtomicUsize::new(0),
|
||||
bytes_reallocated: AtomicIsize::new(0),
|
||||
inner,
|
||||
/// Provides access to an instrumented instance of the given global
|
||||
/// allocator.
|
||||
#[cfg(feature = "nightly")]
|
||||
pub const fn new(inner: T) -> Self {
|
||||
StatsAlloc {
|
||||
allocations: AtomicUsize::new(0),
|
||||
deallocations: AtomicUsize::new(0),
|
||||
reallocations: AtomicUsize::new(0),
|
||||
bytes_allocated: AtomicUsize::new(0),
|
||||
bytes_deallocated: AtomicUsize::new(0),
|
||||
bytes_reallocated: AtomicIsize::new(0),
|
||||
inner,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides access to an instrumented instance of the given global
|
||||
/// allocator.
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
pub fn new(inner: T) -> Self {
|
||||
StatsAlloc {
|
||||
allocations: AtomicUsize::new(0),
|
||||
deallocations: AtomicUsize::new(0),
|
||||
reallocations: AtomicUsize::new(0),
|
||||
bytes_allocated: AtomicUsize::new(0),
|
||||
bytes_deallocated: AtomicUsize::new(0),
|
||||
bytes_reallocated: AtomicIsize::new(0),
|
||||
inner,
|
||||
/// Provides access to an instrumented instance of the given global
|
||||
/// allocator.
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
pub fn new(inner: T) -> Self {
|
||||
StatsAlloc {
|
||||
allocations: AtomicUsize::new(0),
|
||||
deallocations: AtomicUsize::new(0),
|
||||
reallocations: AtomicUsize::new(0),
|
||||
bytes_allocated: AtomicUsize::new(0),
|
||||
bytes_deallocated: AtomicUsize::new(0),
|
||||
bytes_reallocated: AtomicIsize::new(0),
|
||||
inner,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes a snapshot of the current view of the allocator statistics.
|
||||
pub fn stats(&self) -> Stats {
|
||||
Stats {
|
||||
allocations: self.allocations.load(Ordering::SeqCst),
|
||||
deallocations: self.deallocations.load(Ordering::SeqCst),
|
||||
reallocations: self.reallocations.load(Ordering::SeqCst),
|
||||
bytes_allocated: self.bytes_allocated.load(Ordering::SeqCst),
|
||||
bytes_deallocated: self.bytes_deallocated.load(Ordering::SeqCst),
|
||||
bytes_reallocated: self.bytes_reallocated.load(Ordering::SeqCst),
|
||||
/// Takes a snapshot of the current view of the allocator statistics.
|
||||
pub fn stats(&self) -> Stats {
|
||||
Stats {
|
||||
allocations: self.allocations.load(Ordering::SeqCst),
|
||||
deallocations: self.deallocations.load(Ordering::SeqCst),
|
||||
reallocations: self.reallocations.load(Ordering::SeqCst),
|
||||
bytes_allocated: self.bytes_allocated.load(Ordering::SeqCst),
|
||||
bytes_deallocated: self.bytes_deallocated.load(Ordering::SeqCst),
|
||||
bytes_reallocated: self.bytes_reallocated.load(Ordering::SeqCst),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub for Stats {
|
||||
type Output = Stats;
|
||||
type Output = Stats;
|
||||
|
||||
fn sub(mut self, rhs: Self) -> Self::Output {
|
||||
self -= rhs;
|
||||
self
|
||||
}
|
||||
fn sub(mut self, rhs: Self) -> Self::Output {
|
||||
self -= rhs;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::SubAssign for Stats {
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
self.allocations -= rhs.allocations;
|
||||
self.deallocations -= rhs.deallocations;
|
||||
self.reallocations -= rhs.reallocations;
|
||||
self.bytes_allocated -= rhs.bytes_allocated;
|
||||
self.bytes_deallocated -= rhs.bytes_deallocated;
|
||||
self.bytes_reallocated -= rhs.bytes_reallocated;
|
||||
}
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
self.allocations -= rhs.allocations;
|
||||
self.deallocations -= rhs.deallocations;
|
||||
self.reallocations -= rhs.reallocations;
|
||||
self.bytes_allocated -= rhs.bytes_allocated;
|
||||
self.bytes_deallocated -= rhs.bytes_deallocated;
|
||||
self.bytes_reallocated -= rhs.bytes_reallocated;
|
||||
}
|
||||
}
|
||||
|
||||
/// A snapshot of the allocation statistics, which can be used to determine
|
||||
/// allocation changes while the `Region` is alive.
|
||||
#[derive(Debug)]
|
||||
pub struct Region<'a, T: GlobalAlloc> {
|
||||
alloc: &'a StatsAlloc<T>,
|
||||
initial_stats: Stats,
|
||||
alloc: &'a StatsAlloc<T>,
|
||||
initial_stats: Stats,
|
||||
}
|
||||
|
||||
impl<'a, T: GlobalAlloc + 'a> Region<'a, T> {
|
||||
/// Creates a new region using statistics from the given instrumented
|
||||
/// allocator.
|
||||
#[inline]
|
||||
pub fn new(alloc: &'a StatsAlloc<T>) -> Self {
|
||||
Region {
|
||||
alloc,
|
||||
initial_stats: alloc.stats(),
|
||||
/// Creates a new region using statistics from the given instrumented
|
||||
/// allocator.
|
||||
#[inline]
|
||||
pub fn new(alloc: &'a StatsAlloc<T>) -> Self {
|
||||
Region {
|
||||
alloc,
|
||||
initial_stats: alloc.stats(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the statistics as of instantiation or the last reset.
|
||||
#[inline]
|
||||
pub fn initial(&self) -> Stats {
|
||||
self.initial_stats
|
||||
}
|
||||
/// Returns the statistics as of instantiation or the last reset.
|
||||
#[inline]
|
||||
pub fn initial(&self) -> Stats {
|
||||
self.initial_stats
|
||||
}
|
||||
|
||||
/// Returns the difference between the currently reported statistics and
|
||||
/// those provided by `initial()`.
|
||||
#[inline]
|
||||
pub fn change(&self) -> Stats {
|
||||
self.alloc.stats() - self.initial_stats
|
||||
}
|
||||
/// Returns the difference between the currently reported statistics and
|
||||
/// those provided by `initial()`.
|
||||
#[inline]
|
||||
pub fn change(&self) -> Stats {
|
||||
self.alloc.stats() - self.initial_stats
|
||||
}
|
||||
|
||||
/// Returns the difference between the currently reported statistics and
|
||||
/// those provided by `initial()`, resetting initial to the latest
|
||||
/// reported statistics.
|
||||
#[inline]
|
||||
pub fn change_and_reset(&mut self) -> Stats {
|
||||
let latest = self.alloc.stats();
|
||||
let diff = latest - self.initial_stats;
|
||||
self.initial_stats = latest;
|
||||
diff
|
||||
}
|
||||
/// Returns the difference between the currently reported statistics and
|
||||
/// those provided by `initial()`, resetting initial to the latest
|
||||
/// reported statistics.
|
||||
#[inline]
|
||||
pub fn change_and_reset(&mut self) -> Stats {
|
||||
let latest = self.alloc.stats();
|
||||
let diff = latest - self.initial_stats;
|
||||
self.initial_stats = latest;
|
||||
diff
|
||||
}
|
||||
|
||||
/// Resets the initial initial to the latest reported statistics from the
|
||||
/// referenced allocator.
|
||||
#[inline]
|
||||
pub fn reset(&mut self) {
|
||||
self.initial_stats = self.alloc.stats();
|
||||
}
|
||||
/// Resets the initial initial to the latest reported statistics from the
|
||||
/// referenced allocator.
|
||||
#[inline]
|
||||
pub fn reset(&mut self) {
|
||||
self.initial_stats = self.alloc.stats();
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a, T: GlobalAlloc + 'a> GlobalAlloc for &'a StatsAlloc<T> {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
(*self).alloc(layout)
|
||||
}
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
(*self).alloc(layout)
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
(*self).dealloc(ptr, layout)
|
||||
}
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
(*self).dealloc(ptr, layout)
|
||||
}
|
||||
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||
(*self).alloc_zeroed(layout)
|
||||
}
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||
(*self).alloc_zeroed(layout)
|
||||
}
|
||||
|
||||
unsafe fn realloc(
|
||||
&self,
|
||||
ptr: *mut u8,
|
||||
layout: Layout,
|
||||
new_size: usize,
|
||||
) -> *mut u8 {
|
||||
(*self).realloc(ptr, layout, new_size)
|
||||
}
|
||||
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
||||
(*self).realloc(ptr, layout, new_size)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: GlobalAlloc> GlobalAlloc for StatsAlloc<T> {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
self.allocations.fetch_add(1, Ordering::SeqCst);
|
||||
self
|
||||
.bytes_allocated
|
||||
.fetch_add(layout.size(), Ordering::SeqCst);
|
||||
self.inner.alloc(layout)
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
self.deallocations.fetch_add(1, Ordering::SeqCst);
|
||||
self
|
||||
.bytes_deallocated
|
||||
.fetch_add(layout.size(), Ordering::SeqCst);
|
||||
self.inner.dealloc(ptr, layout)
|
||||
}
|
||||
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||
self.allocations.fetch_add(1, Ordering::SeqCst);
|
||||
self
|
||||
.bytes_allocated
|
||||
.fetch_add(layout.size(), Ordering::SeqCst);
|
||||
self.inner.alloc_zeroed(layout)
|
||||
}
|
||||
|
||||
unsafe fn realloc(
|
||||
&self,
|
||||
ptr: *mut u8,
|
||||
layout: Layout,
|
||||
new_size: usize,
|
||||
) -> *mut u8 {
|
||||
self.reallocations.fetch_add(1, Ordering::SeqCst);
|
||||
match new_size.cmp(&layout.size()) {
|
||||
CmpOrdering::Greater => {
|
||||
let difference = new_size - layout.size();
|
||||
self.bytes_allocated.fetch_add(difference, Ordering::SeqCst);
|
||||
}
|
||||
CmpOrdering::Less => {
|
||||
let difference = layout.size() - new_size;
|
||||
self
|
||||
.bytes_deallocated
|
||||
.fetch_add(difference, Ordering::SeqCst);
|
||||
}
|
||||
_ => {}
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
self.allocations.fetch_add(1, Ordering::SeqCst);
|
||||
self.bytes_allocated
|
||||
.fetch_add(layout.size(), Ordering::SeqCst);
|
||||
self.inner.alloc(layout)
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
self.deallocations.fetch_add(1, Ordering::SeqCst);
|
||||
self.bytes_deallocated
|
||||
.fetch_add(layout.size(), Ordering::SeqCst);
|
||||
self.inner.dealloc(ptr, layout)
|
||||
}
|
||||
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||
self.allocations.fetch_add(1, Ordering::SeqCst);
|
||||
self.bytes_allocated
|
||||
.fetch_add(layout.size(), Ordering::SeqCst);
|
||||
self.inner.alloc_zeroed(layout)
|
||||
}
|
||||
|
||||
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
||||
self.reallocations.fetch_add(1, Ordering::SeqCst);
|
||||
match new_size.cmp(&layout.size()) {
|
||||
CmpOrdering::Greater => {
|
||||
let difference = new_size - layout.size();
|
||||
self.bytes_allocated.fetch_add(difference, Ordering::SeqCst);
|
||||
}
|
||||
CmpOrdering::Less => {
|
||||
let difference = layout.size() - new_size;
|
||||
self.bytes_deallocated
|
||||
.fetch_add(difference, Ordering::SeqCst);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.bytes_reallocated.fetch_add(
|
||||
new_size.wrapping_sub(layout.size()) as isize,
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
self.inner.realloc(ptr, layout, new_size)
|
||||
}
|
||||
self.bytes_reallocated.fetch_add(
|
||||
new_size.wrapping_sub(layout.size()) as isize,
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
self.inner.realloc(ptr, layout, new_size)
|
||||
}
|
||||
}
|
||||
|
|
11
rustfmt.toml
11
rustfmt.toml
|
@ -1,11 +0,0 @@
|
|||
comment_width = 80
|
||||
group_imports = "StdExternalCrate"
|
||||
imports_granularity = "Module"
|
||||
max_width = 80
|
||||
newline_style = "Unix"
|
||||
normalize_comments = true
|
||||
normalize_doc_attributes = true
|
||||
reorder_impl_items = true
|
||||
tab_spaces = 2
|
||||
version = "Two"
|
||||
wrap_comments = true
|
Loading…
Reference in New Issue