Reset updater

This commit is contained in:
Nathan McCarty 2021-12-23 13:11:49 -05:00
parent 60ec7b5e22
commit fcd11b66bd
Signed by: thatonelutenist
GPG Key ID: D70DA3DD4D1E9F96
8 changed files with 1772 additions and 287 deletions

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
**/result/** **/result
**/target **/target

View File

@ -10,11 +10,7 @@
utils.lib.eachSystem [ "x86_64-linux" ] (system: utils.lib.eachSystem [ "x86_64-linux" ] (system:
let let
sources = builtins.fromJSON (builtins.readFile ./sources.json); sources = builtins.fromJSON (builtins.readFile ./sources.json);
in buildAdoptLike = with import nixpkgs {system = system;}; name: value:
with import nixpkgs { system = system; };
{
packages.jdks = builtins.mapAttrs
(name: value:
let let
cpuName = stdenv.hostPlatform.parsed.cpu.name; cpuName = stdenv.hostPlatform.parsed.cpu.name;
runtimeDependencies = [ runtimeDependencies = [
@ -26,12 +22,12 @@
runtimeLibraryPath = lib.makeLibraryPath runtimeDependencies; runtimeLibraryPath = lib.makeLibraryPath runtimeDependencies;
in in
stdenv.mkDerivation rec { stdenv.mkDerivation rec {
name = "jdk${value.version}"; name = "jdk${toString value.major_version}";
src = builtins.fetchurl { src = builtins.fetchurl {
url = value.url; url = value.link;
sha256 = value.sha256; sha256 = value.sha256;
}; };
version = value.version; version = value.java_version;
buildInputs = with pkgs; [ buildInputs = with pkgs; [
alsa-lib alsa-lib
fontconfig fontconfig
@ -83,17 +79,24 @@
find "$out" -name libfontmanager.so -exec \ find "$out" -name libfontmanager.so -exec \
patchelf --add-needed libfontconfig.so {} \; patchelf --add-needed libfontconfig.so {} \;
''; '';
} };
in
with import nixpkgs { system = system; };
{
packages.adoptium = (builtins.mapAttrs
(name: value:
buildAdoptLike name value
) )
sources.${system}.versions; sources.${system}.adoptium.versions) // {
latest = buildAdoptLike "latest" sources.${system}.adoptium.latest;
packages.jdk = self.packages.jdks.18; stable = buildAdoptLike "stable" sources.${system}.adoptium.stable;
packages.jdk-lts = self.packages.jdks.17; lts = buildAdoptLike "lts" sources.${system}.adoptium.lts;
packages.jdk18 = self.packages.jdks.18; };
packages.jdk17 = self.packages.jdks.17;
packages.jdk16 = self.packages.jdks.16; packages.latest = self.packages.${system}.adoptium.latest;
packages.jdk11 = self.packages.jdks.11; packages.stable = self.packages.${system}.adoptium.stable;
packages.lts = self.packages.${system}.adoptium.lts;
defaultPackage = self.packages.jdks.18;
}); defaultPackage = self.packages.${system}.stable;
} });
}

1
result
View File

@ -1 +0,0 @@
/nix/store/j8c42s14ri5kryqz5fjcjqd736z73bpi-jdk11.0.13+8

View File

@ -1,29 +1,63 @@
{ {
"x86_64-linux": { "x86_64-linux": {
"versions": { "adoptium": {
"17": { "versions": {
"major_version": "17", "jdk18": {
"version": "17.0.0+35", "link": "https://github.com/adoptium/temurin18-binaries/releases/download/jdk18-2021-12-17-07-56-beta/OpenJDK18-jdk_x64_linux_hotspot_2021-12-17-07-56.tar.gz",
"url": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17u-2021-10-25-08-48-beta/OpenJDK17U-jdk_x64_linux_hotspot_2021-10-25-08-48.tar.gz", "major_version": 18,
"sha256": "0lb5mkh752x6d5yvlkcgdr60pas1qxk00jwlr7rm3566ry852vgf" "java_version": "18-beta+28-202112170011",
"early_access": true,
"sha256": "05jb4qdzb7v8arm1ysghrkyj53k2qaxsb2gnzlkgivgpnv91jbll"
},
"jdk17": {
"link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.1%2B12/OpenJDK17U-jdk_x64_linux_hotspot_17.0.1_12.tar.gz",
"major_version": 17,
"java_version": "17.0.1+12",
"early_access": false,
"sha256": "1dj8aky3wv3c6b9r11dsd1rpwz6bnnjc7kzbxqpm5f6bdlkqr8bf"
},
"jdk11": {
"link": "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.13%2B8/OpenJDK11U-jdk_x64_linux_hotspot_11.0.13_8.tar.gz",
"major_version": 11,
"java_version": "11.0.13+8",
"early_access": false,
"sha256": "0c4fa8kbprpgq2h2zv04x85d2jxab8nlyias2dj4x2acpqs0q71v"
},
"jdk8": {
"link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u312-b07/OpenJDK8U-jdk_x64_linux_hotspot_8u312b07.tar.gz",
"major_version": 8,
"java_version": "1.8.0_312-b07",
"early_access": false,
"sha256": "022aqglsvs1px07ri8z5kn3lpbp3z90dc6jixdz0mdl3744836b9"
},
"jdk16": {
"link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_linux_hotspot_16.0.2_7.tar.gz",
"major_version": 16,
"java_version": "16.0.2+7",
"early_access": false,
"sha256": "0b1wayg38rckzm1fy4pdm1a1bmjvwvw0vpbxzy7a4nd3fis6sg9j"
}
}, },
"18": { "latest": {
"major_version": "18", "link": "https://github.com/adoptium/temurin18-binaries/releases/download/jdk18-2021-12-17-07-56-beta/OpenJDK18-jdk_x64_linux_hotspot_2021-12-17-07-56.tar.gz",
"version": "18.0.0+28", "major_version": 18,
"url": "https://github.com/adoptium/temurin18-binaries/releases/download/jdk18-2021-12-17-07-56-beta/OpenJDK18-jdk_x64_linux_hotspot_2021-12-17-07-56.tar.gz", "java_version": "18-beta+28-202112170011",
"early_access": true,
"sha256": "05jb4qdzb7v8arm1ysghrkyj53k2qaxsb2gnzlkgivgpnv91jbll" "sha256": "05jb4qdzb7v8arm1ysghrkyj53k2qaxsb2gnzlkgivgpnv91jbll"
}, },
"11": { "stable": {
"major_version": "11", "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.1%2B12/OpenJDK17U-jdk_x64_linux_hotspot_17.0.1_12.tar.gz",
"version": "11.0.13+8", "major_version": 17,
"url": "https://github.com/adoptium/temurin11-binaries/releases/download/jdk11u-2021-11-05-11-35-beta/OpenJDK11U-jdk_x64_linux_hotspot_2021-11-05-11-35.tar.gz", "java_version": "17.0.1+12",
"sha256": "09p60182vz31wxnp43ghlp1q928xfql0wnk7g852s1wiwjr26dm0" "early_access": false,
"sha256": "1dj8aky3wv3c6b9r11dsd1rpwz6bnnjc7kzbxqpm5f6bdlkqr8bf"
}, },
"16": { "lts": {
"major_version": "16", "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.1%2B12/OpenJDK17U-jdk_x64_linux_hotspot_17.0.1_12.tar.gz",
"version": "16.0.1+9", "major_version": 17,
"url": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk16u-2021-07-22-01-18-beta/OpenJDK16U-jdk_x64_linux_hotspot_2021-07-22-01-18.tar.gz", "java_version": "17.0.1+12",
"sha256": "0rgyp5jrwqjxz0ajk94vmwvagk88p5a41sm2ynckq3p7sg992ym0" "early_access": false,
"sha256": "1dj8aky3wv3c6b9r11dsd1rpwz6bnnjc7kzbxqpm5f6bdlkqr8bf"
} }
} }
} }

1414
updater/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -6,8 +6,8 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
color-eyre = { version = "0.5.11", default-features = false } async-std = { version = "1.10.0", features = ["std", "async-global-executor", "futures-lite", "num_cpus", "attributes"], default-features = false }
color-eyre = "0.5.11"
serde = { version = "1.0.132", features = ["derive"] } serde = { version = "1.0.132", features = ["derive"] }
serde_json = "1.0.73" serde_json = "1.0.73"
ureq = { version = "2.3.1", features = ["json"] } surf = { version = "2.3.2", features = ["h1-client-rustls", "encoding"], default-features = false }
url = "2.2.2"

216
updater/src/adoptium.rs Normal file
View File

@ -0,0 +1,216 @@
use std::collections::HashMap;
use color_eyre::{
eyre::{eyre, Context, Result},
Help, SectionExt,
};
use serde::{Deserialize, Serialize};
use surf::Client;
/// Page size
pub const PAGE_SIZE: u64 = 10;
/// Response from `/v3/info/available_releases` endpoint
#[derive(Deserialize, Serialize, Debug)]
pub struct AvailableReleases {
pub available_lts_releases: Vec<u64>,
pub available_releases: Vec<u64>,
pub most_recent_feature_release: u64,
pub most_recent_feature_version: u64,
pub tip_version: u64,
}
/// Package for a particular binary
#[derive(Deserialize, Serialize, Debug)]
pub struct Package {
checksum: String,
checksum_link: String,
download_count: u64,
pub link: String,
metadata_link: String,
name: String,
size: u64,
}
/// Information about a particular binary
#[derive(Deserialize, Serialize, Debug)]
pub struct Binary {
architecture: String,
download_count: u64,
heap_size: String,
image_type: String,
jvm_impl: String,
os: String,
pub package: Package,
project: String,
scm_ref: String,
updated_at: String,
}
/// Information about a source
#[derive(Deserialize, Serialize, Debug)]
pub struct Source {
link: String,
name: String,
size: u64,
}
/// Version data
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
pub struct VersionData {
pub build: u64,
pub major: u64,
pub minor: u64,
pub openjdk_version: String,
pub security: u64,
pub semver: String,
}
impl PartialOrd for VersionData {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match self.major.partial_cmp(&other.major) {
Some(std::cmp::Ordering::Equal) => {}
ord => return ord,
}
match self.minor.partial_cmp(&other.minor) {
Some(std::cmp::Ordering::Equal) => {}
ord => return ord,
}
match self.security.partial_cmp(&other.security) {
Some(std::cmp::Ordering::Equal) => {}
ord => return ord,
}
self.build.partial_cmp(&other.build)
}
}
impl Ord for VersionData {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.partial_cmp(other).unwrap()
}
}
/// Information about a particular feature release
#[derive(Deserialize, Serialize, Debug)]
pub struct Release {
pub binaries: Vec<Binary>,
download_count: u64,
id: String,
release_link: String,
pub release_type: String,
source: Option<Source>,
timestamp: String,
updated_at: String,
vendor: String,
pub version_data: VersionData,
}
impl PartialEq for Release {
fn eq(&self, other: &Self) -> bool {
self.version_data == other.version_data
}
}
impl Eq for Release {}
impl PartialOrd for Release {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.version_data.partial_cmp(&other.version_data)
}
}
impl Ord for Release {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.version_data.cmp(&other.version_data)
}
}
/// Attempts to get the available releases
pub async fn get_available_releases(client: &Client) -> Result<AvailableReleases> {
let endpoint = "https://api.adoptium.net/v3/info/available_releases";
client
.get(endpoint)
.recv_json()
.await
.map_err(|e| eyre!(e))
.context("Failed to request available versions from adoptium")
.with_section(|| endpoint.to_string().header("Failed Request:"))
}
/// Release query struct
#[derive(Deserialize, Serialize, Debug)]
pub struct ReleaseQuery {
architecture: String,
heap_size: String,
image_type: String,
os: String,
page_size: u64,
project: String,
}
/// Attempts to get the release info for a particular version
pub async fn get_release(client: &Client, version: u64, release_type: &str) -> Result<Release> {
let endpoint = format!(
"https://api.adoptium.net/v3/assets/feature_releases/{}/{}",
version, release_type
);
let request = client
.get(endpoint)
.query(&ReleaseQuery {
architecture: "x64".to_string(),
heap_size: "normal".to_string(),
image_type: "jdk".to_string(),
os: "linux".to_string(),
page_size: PAGE_SIZE,
project: "jdk".to_string(),
})
.map_err(|e| eyre!(e))
.context("Failed to build request")?
.build();
let query = request.url().as_str().to_string();
let mut releases: Vec<Release> = client
.recv_json(request)
.await
.map_err(|e| eyre!(e))
.context("Failed to get release information from adoptium")
.with_section(move || query.header("Failed Request"))?;
releases.sort();
match releases.pop() {
Some(release) => Ok(release),
None => Err(eyre!("Adoptium endpoint did not return any valid releases")),
}
}
/// Attempts to get all the versions
pub async fn get_releases(client: &Client) -> Result<HashMap<u64, Release>> {
let available = get_available_releases(client)
.await
.context("Failed to list adoptium releases")?;
let mut output = HashMap::new();
// Get the generally available version of all the available releases
for version in available.available_releases {
let release = get_release(client, version, "ga").await.with_context(|| {
format!(
"Failed to get version {} from the adoptium archive",
version
)
})?;
output.insert(version, release);
}
// See if we already have the latest version
if output.contains_key(&available.most_recent_feature_version) {
// Go ahead and return
Ok(output)
} else {
let version = available.most_recent_feature_version;
// Otherwise try to get an EA version of it
let release = get_release(client, version, "ea").await.with_context(|| {
format!(
"Failed to get version {} (latest) from the adoptium archive",
version
)
})?;
output.insert(version, release);
Ok(output)
}
}

View File

@ -1,227 +1,118 @@
use std::collections::{HashMap, HashSet}; use std::{collections::HashMap, process::Command};
use std::process::Command;
use color_eyre::{ use color_eyre::{
eyre::{bail, Context, ContextCompat, Result}, eyre::{eyre, Context, Result},
Help, SectionExt, Section, SectionExt,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use surf::Client;
fn main() -> Result<()> { /// Adoptium API
color_eyre::install()?; pub mod adoptium;
// Get the available versions /// Java release struct
let versions = get_all_versions()?; #[derive(Deserialize, Serialize, Debug, Clone)]
// Uniqueify them pub struct Release {
let mut slugs: HashMap<String, (Release, String)> = HashMap::new(); link: String,
for version in versions { major_version: u64,
if let Ok(url) = get_url(&version) { java_version: String,
let slug = version.to_slug(); early_access: bool,
let entry = slugs.entry(slug).or_insert((version.clone(), url.clone()));
if version > entry.0 {
*entry = (version, url)
}
}
}
let mut sources = Sources {
versions: HashMap::new(),
};
for (_slug, (version, url)) in slugs {
sources.add_release(&version, &url)?;
}
let mut output: HashMap<String, Sources> = HashMap::new();
output.insert("x86_64-linux".to_string(), sources);
let json_output =
serde_json::to_string_pretty(&output).context("Failed to serialize output")?;
println!("{}", json_output);
Ok(())
}
/// Serde serialization format
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
struct Sources {
versions: HashMap<String, Source>,
}
impl Sources {
fn add_release(&mut self, release: &Release, url: &str) -> Result<()> {
let version = release.to_java_version();
let source = Source {
major_version: release.major.to_string(),
version,
url: url.to_string(),
sha256: get_sha256(url)?,
};
self.versions.insert(release.major.to_string(), source);
Ok(())
}
}
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
struct Source {
major_version: String,
version: String,
url: String,
sha256: String, sha256: String,
} }
/// Serde formatting struct /// Sources serialization struct
#[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug, Clone)] #[derive(Deserialize, Serialize, Debug, Clone)]
struct Release { pub struct Sources {
build: usize, versions: HashMap<String, Release>,
major: usize, latest: Release,
minor: usize, stable: Release,
openjdk_version: String, lts: Release,
security: usize,
semver: String,
} }
impl PartialOrd for Release { /// System serialization struct
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { #[derive(Deserialize, Serialize, Debug, Clone)]
match self.build.partial_cmp(&other.build) { pub struct System {
Some(core::cmp::Ordering::Equal) => {} adoptium: Sources,
ord => return ord, }
}
match self.major.partial_cmp(&other.major) { impl TryFrom<adoptium::Release> for Release {
Some(core::cmp::Ordering::Equal) => {} type Error = color_eyre::eyre::Report;
ord => return ord,
} fn try_from(value: adoptium::Release) -> Result<Self> {
match self.minor.partial_cmp(&other.minor) { if value.binaries.len() == 1 {
Some(core::cmp::Ordering::Equal) => {} let package = &value.binaries[0].package;
ord => return ord, Ok(Release {
} link: package.link.clone(),
match self.openjdk_version.partial_cmp(&other.openjdk_version) { major_version: value.version_data.major,
Some(core::cmp::Ordering::Equal) => {} java_version: value.version_data.openjdk_version,
ord => return ord, early_access: value.release_type == "ea",
} sha256: get_sha256(&package.link).context("Failed to prefetch package")?,
match self.security.partial_cmp(&other.security) { })
Some(core::cmp::Ordering::Equal) => {} } else {
ord => return ord, Err(eyre!(
} "Adoptium release had an incorrect number of binaries"
match self.openjdk_version.partial_cmp(&other.openjdk_version) { ))
Some(core::cmp::Ordering::Equal) => Some(core::cmp::Ordering::Equal),
_ => {
let x = self.openjdk_version.split('-').collect::<Vec<_>>();
let x = x[x.len() - 1];
let y = other.openjdk_version.split('-').collect::<Vec<_>>();
let y = y[y.len() - 1];
x.partial_cmp(y)
}
} }
} }
} }
impl Ord for Release { #[async_std::main]
fn cmp(&self, other: &Self) -> std::cmp::Ordering { async fn main() -> Result<()> {
self.partial_cmp(other).unwrap() color_eyre::install()?;
} // Create a client
let client = Client::new();
// Get list of releases from adoptium, we'll use this for some other things
let available = adoptium::get_available_releases(&client)
.await
.context("Failed to get list of available releases")?;
let lts_version = available
.available_lts_releases
.iter()
.copied()
.max()
.expect("No LTSs?");
// Get adoptium releases
let adoptium_releases = get_adoptium_releases(&client).await?;
// Spit out to the serialization format
let adoptium = Sources {
versions: adoptium_releases
.clone()
.into_iter()
.map(|(k, v)| (format!("jdk{}", k), v))
.collect(),
latest: adoptium_releases
.get(&available.most_recent_feature_version)
.expect("Missing release")
.clone(),
stable: adoptium_releases
.get(&available.most_recent_feature_release)
.expect("Missing release")
.clone(),
lts: adoptium_releases
.get(&lts_version)
.expect("Missing release")
.clone(),
};
let system = System { adoptium };
let mut systems = HashMap::new();
systems.insert("x86_64-linux".to_string(), system);
let output = serde_json::to_string_pretty(&systems).context("Failed to encode sources")?;
println!("{}", output);
Ok(())
} }
impl Release { /// Get the releases from adoptium
fn to_slug(&self) -> String { pub async fn get_adoptium_releases(client: &Client) -> Result<HashMap<u64, Release>> {
format!("1.{}.{}", self.major, self.minor) let releases: Result<HashMap<u64, Release>> = adoptium::get_releases(&client)
} .await?
fn to_java_version(&self) -> String {
format!(
"{}.{}.{}+{}",
self.major, self.minor, self.security, self.build
)
}
}
/// Serde formatting struct
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
struct Versions {
versions: Vec<Release>,
}
/// Get a page of the versions
fn get_versions_page(page: usize) -> Result<Vec<Release>> {
let page = format!("{}", page);
let request = ureq::get("https://api.adoptium.net/v3/info/release_versions")
.query("architecture", "x64")
.query("image_type", "jdk")
.query("os", "linux")
.query("page", &page)
.query("page_size", "50")
.query("project", "jdk");
let url = request.url().to_string();
let response = request
.call()
.with_section(|| format!("Page: {} Url: {}", page, url).header("Failed Request:"))
.context("Failed getting page of versions list")?;
let versions: Versions = response
.into_json()
.with_section(|| format!("Page: {} Url: {}", page, url).header("Failed Request:"))
.context("Failed deserializing page of versions list")?;
Ok(versions.versions)
}
/// Get all the versions available
fn get_all_versions() -> Result<HashSet<Release>> {
let mut versions = HashSet::new();
// Go through the pages until we hit a 404
let mut page_number = 0;
// Err early if the first page fails, so we can have a more useful context message
let mut page =
Ok(get_versions_page(0).context("Failed getting first page in get_all_versions")?);
while let Ok(current_page) = page {
for version in current_page {
versions.insert(version);
}
page_number += 1;
page = get_versions_page(page_number).context("Ran out of pages");
}
Ok(versions)
}
/// Serde deserialization type
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
struct VersionInfo {
binaries: Vec<BinaryInfo>,
}
/// Serde deserialization type
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
struct BinaryInfo {
package: PackageInfo,
}
/// Serde deserialization type
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
struct PackageInfo {
link: String,
name: String,
}
/// Gets the url for the latest release of a version
fn get_url(version: &Release) -> Result<String> {
let request = ureq::get(&format!(
"https://api.adoptium.net/v3/assets/version/{}",
version.openjdk_version
))
.query("architecture", "x64")
.query("image_type", "jdk")
.query("os", "linux")
.query("page", "0")
.query("page_size", "1")
.query("project", "jdk");
let url = request.url().to_string();
let response = request
.call()
.with_section(|| format!("Url: {}", url).header("Failed Request"))
.context("Failed requesting version information")?;
let version_info: Vec<VersionInfo> = response
.into_json()
.with_section(|| format!("Url: {}", url).header("Failed Request"))
.context("Failed to deserialize response for version information")?;
let version_info = version_info
.into_iter() .into_iter()
.next() .map(|(key, val)| match val.try_into() {
.context("Nothing providred")?; Ok(val) => Ok((key, val)),
Err(err) => Err(err),
})
.collect();
match version_info.binaries.get(0) { releases.context("Failed getting release from adoptium")
Some(binary_info) => Ok(binary_info.package.link.clone()),
None => bail!("Binary was missing!"),
}
} }
/// Gets the nix sha256 for a url /// Gets the nix sha256 for a url