Parse manifest
This commit is contained in:
parent
f90187c914
commit
670dbaee7c
105
src/repo/mod.rs
105
src/repo/mod.rs
@ -1,17 +1,21 @@
|
||||
use crate::manifest::Manifest;
|
||||
use crate::repo::github::GithubRepo;
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use apk::manifest::Sdk;
|
||||
use apk::res::Chunk;
|
||||
use apk::AndroidManifest;
|
||||
use async_zip::tokio::read::seek::ZipFileReader;
|
||||
use async_zip::ZipFile;
|
||||
use log::info;
|
||||
use log::{debug, info, warn};
|
||||
use nostr_sdk::async_utility::futures_util::TryStreamExt;
|
||||
use nostr_sdk::prelude::{hex, StreamExt};
|
||||
use reqwest::Url;
|
||||
use semver::Version;
|
||||
use serde::Deserialize;
|
||||
use sha2::Digest;
|
||||
use std::collections::HashMap;
|
||||
use std::env::temp_dir;
|
||||
use std::io::Cursor;
|
||||
use std::path::{Path, PathBuf};
|
||||
use tokio::fs::File;
|
||||
use tokio::io::{AsyncWriteExt, BufReader};
|
||||
@ -144,10 +148,9 @@ async fn load_apk_artifact(path: &Path) -> Result<RepoArtifact> {
|
||||
})
|
||||
.ok_or(anyhow!("missing AndroidManifest file"))?;
|
||||
let mut manifest = zip.reader_with_entry(idx).await?;
|
||||
let mut manifest_data = String::with_capacity(8192);
|
||||
manifest.read_to_string_checked(&mut manifest_data).await?;
|
||||
info!("Successfully loaded AndroidManifest: {}", &manifest_data);
|
||||
let manifest: AndroidManifest = quick_xml::de::from_str(&manifest_data)?;
|
||||
let mut manifest_data = Vec::with_capacity(8192);
|
||||
manifest.read_to_end_checked(&mut manifest_data).await?;
|
||||
let manifest: AndroidManifest = parse_android_manifest(&manifest_data)?;
|
||||
|
||||
Ok(RepoArtifact {
|
||||
name: path.file_name().unwrap().to_str().unwrap().to_string(),
|
||||
@ -160,3 +163,95 @@ async fn load_apk_artifact(path: &Path) -> Result<RepoArtifact> {
|
||||
metadata: ArtifactMetadata::APK { manifest },
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_android_manifest(data: &Vec<u8>) -> Result<AndroidManifest> {
|
||||
let chunks = if let Chunk::Xml(chunks) = Chunk::parse(&mut Cursor::new(data))? {
|
||||
chunks
|
||||
} else {
|
||||
bail!("Invalid AndroidManifest file");
|
||||
};
|
||||
|
||||
let strings = if let Chunk::StringPool(strings, _) = &chunks[0] {
|
||||
HashMap::from_iter(
|
||||
strings
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, s)| (s.to_string(), i as i32)),
|
||||
)
|
||||
} else {
|
||||
bail!("invalid manifest 1");
|
||||
};
|
||||
|
||||
let mut res = AndroidManifest::default();
|
||||
res.package = find_value_in(&strings, &chunks, "manifest", "package");
|
||||
res.version_code =
|
||||
find_value_in(&strings, &chunks, "manifest", "versionCode").and_then(|v| v.parse().ok());
|
||||
res.version_name = find_value_in(&strings, &chunks, "manifest", "versionName");
|
||||
res.compile_sdk_version = find_value_in(&strings, &chunks, "manifest", "compileSdkVersion")
|
||||
.and_then(|v| v.parse().ok());
|
||||
res.compile_sdk_version_codename =
|
||||
find_value_in(&strings, &chunks, "manifest", "compileSdkVersionCodename")
|
||||
.and_then(|v| v.parse().ok());
|
||||
res.platform_build_version_code =
|
||||
find_value_in(&strings, &chunks, "manifest", "platformBuildVersionCode")
|
||||
.and_then(|v| v.parse().ok());
|
||||
res.platform_build_version_name =
|
||||
find_value_in(&strings, &chunks, "manifest", "platformBuildVersionName")
|
||||
.and_then(|v| v.parse().ok());
|
||||
|
||||
res.sdk.min_sdk_version =
|
||||
find_value_in(&strings, &chunks, "uses-sdk", "minSdkVersion").and_then(|v| v.parse().ok());
|
||||
res.sdk.target_sdk_version = find_value_in(&strings, &chunks, "uses-sdk", "targetSdkVersion")
|
||||
.and_then(|v| v.parse().ok());
|
||||
res.sdk.max_sdk_version =
|
||||
find_value_in(&strings, &chunks, "uses-sdk", "maxSdkVersion").and_then(|v| v.parse().ok());
|
||||
|
||||
res.application.theme = find_value_in(&strings, &chunks, "application", "theme");
|
||||
res.application.label = find_value_in(&strings, &chunks, "application", "label");
|
||||
res.application.icon = find_value_in(&strings, &chunks, "application", "icon");
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn find_value_in(
|
||||
strings: &HashMap<String, i32>,
|
||||
chunks: &Vec<Chunk>,
|
||||
node: &str,
|
||||
attr: &str,
|
||||
) -> Option<String> {
|
||||
let idx_node = if let Some(i) = strings.get(node) {
|
||||
*i
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let idx_attr = if let Some(i) = strings.get(attr) {
|
||||
*i
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
chunks.iter().find_map(|chunk| {
|
||||
if let Chunk::XmlStartElement(_, el, attrs) = chunk {
|
||||
match el.name {
|
||||
x if x == idx_node => attrs.iter().find(|e| e.name == idx_attr).and_then(|e| {
|
||||
debug!("{}, {}, {:?}", node, attr, e);
|
||||
match e.typed_value.data_type {
|
||||
3 => strings
|
||||
.iter()
|
||||
.find(|(_, v)| **v == e.raw_value)
|
||||
.map(|(k, _)| k.clone()),
|
||||
16 => Some(e.typed_value.data.to_string()),
|
||||
_ => {
|
||||
warn!("unknown data type {},{},{:?}", node, attr, e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user