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::manifest::Manifest;
|
||||||
use crate::repo::github::GithubRepo;
|
use crate::repo::github::GithubRepo;
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
|
use apk::manifest::Sdk;
|
||||||
|
use apk::res::Chunk;
|
||||||
use apk::AndroidManifest;
|
use apk::AndroidManifest;
|
||||||
use async_zip::tokio::read::seek::ZipFileReader;
|
use async_zip::tokio::read::seek::ZipFileReader;
|
||||||
use async_zip::ZipFile;
|
use async_zip::ZipFile;
|
||||||
use log::info;
|
use log::{debug, info, warn};
|
||||||
use nostr_sdk::async_utility::futures_util::TryStreamExt;
|
use nostr_sdk::async_utility::futures_util::TryStreamExt;
|
||||||
use nostr_sdk::prelude::{hex, StreamExt};
|
use nostr_sdk::prelude::{hex, StreamExt};
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sha2::Digest;
|
use sha2::Digest;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::env::temp_dir;
|
use std::env::temp_dir;
|
||||||
|
use std::io::Cursor;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use tokio::fs::File;
|
use tokio::fs::File;
|
||||||
use tokio::io::{AsyncWriteExt, BufReader};
|
use tokio::io::{AsyncWriteExt, BufReader};
|
||||||
@ -144,10 +148,9 @@ async fn load_apk_artifact(path: &Path) -> Result<RepoArtifact> {
|
|||||||
})
|
})
|
||||||
.ok_or(anyhow!("missing AndroidManifest file"))?;
|
.ok_or(anyhow!("missing AndroidManifest file"))?;
|
||||||
let mut manifest = zip.reader_with_entry(idx).await?;
|
let mut manifest = zip.reader_with_entry(idx).await?;
|
||||||
let mut manifest_data = String::with_capacity(8192);
|
let mut manifest_data = Vec::with_capacity(8192);
|
||||||
manifest.read_to_string_checked(&mut manifest_data).await?;
|
manifest.read_to_end_checked(&mut manifest_data).await?;
|
||||||
info!("Successfully loaded AndroidManifest: {}", &manifest_data);
|
let manifest: AndroidManifest = parse_android_manifest(&manifest_data)?;
|
||||||
let manifest: AndroidManifest = quick_xml::de::from_str(&manifest_data)?;
|
|
||||||
|
|
||||||
Ok(RepoArtifact {
|
Ok(RepoArtifact {
|
||||||
name: path.file_name().unwrap().to_str().unwrap().to_string(),
|
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 },
|
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