use super::chain_specs::chain_spec_generator;
use crate::{Error, up::chain_specs};
use pop_common::{
git::GitHub,
polkadot_sdk::sort_by_latest_stable_version,
sourcing::{
ArchiveFileSpec, Binary,
GitHub::*,
Source,
filters::prefix,
traits::{
Source as SourceT,
enums::{Source as _, *},
},
},
target,
};
use std::{iter::once, path::Path};
use strum::VariantArray as _;
use strum_macros::{EnumProperty, VariantArray};
#[derive(Debug, EnumProperty, PartialEq, VariantArray)]
pub(super) enum RelayChain {
#[strum(props(
Repository = "https://github.com/r0gue-io/polkadot",
Binary = "polkadot",
TagPattern = "polkadot-{version}",
Fallback = "stable2512"
))]
Polkadot,
}
impl SourceT for &RelayChain {
type Error = Error;
fn source(&self) -> Result<Source, Error> {
Ok(match self {
RelayChain::Polkadot => {
let repo = GitHub::parse(self.repository())?;
Source::GitHub(ReleaseArchive {
owner: repo.org,
repository: repo.name,
tag: None,
tag_pattern: self.tag_pattern().map(|t| t.into()),
prerelease: false,
version_comparator: sort_by_latest_stable_version,
fallback: self.fallback().into(),
archive: format!("{}-{}.tar.gz", self.binary(), target()?),
contents: once(self.binary())
.chain(self.workers())
.map(|n| ArchiveFileSpec::new(n.into(), None, true))
.collect(),
latest: None,
})
},
})
}
}
impl RelayChain {
fn workers(&self) -> [&'static str; 2] {
["polkadot-execute-worker", "polkadot-prepare-worker"]
}
}
pub(super) async fn default(
version: Option<&str>,
runtime_version: Option<&str>,
chain: &str,
cache: &Path,
) -> Result<super::RelayChain, Error> {
from(RelayChain::Polkadot.binary(), version, runtime_version, chain, cache).await
}
pub(super) async fn from(
command: &str,
version: Option<&str>,
runtime_version: Option<&str>,
chain: &str,
cache: &Path,
) -> Result<super::RelayChain, Error> {
if let Some(relay) = RelayChain::VARIANTS
.iter()
.find(|r| command.to_lowercase().ends_with(r.binary()))
{
let name = relay.binary().to_string();
let source = relay
.source()?
.resolve(&name, version, cache, |f| prefix(f, &name))
.await
.into();
let binary = Binary::Source { name, source, cache: cache.to_path_buf() };
let runtime = chain_specs::Runtime::from_chain(chain)
.ok_or(Error::UnsupportedCommand(format!("the relay chain is unsupported: {chain}")))?;
return Ok(super::RelayChain {
runtime,
binary,
workers: relay.workers(),
chain: chain.into(),
chain_spec_generator: chain_spec_generator(chain, runtime_version, cache).await?,
});
}
Err(Error::UnsupportedCommand(format!("the relay chain command is unsupported: {command}")))
}
#[cfg(test)]
mod tests {
use super::{
super::tests::{FALLBACK, RELAY_BINARY_VERSION},
*,
};
use pop_common::polkadot_sdk::sort_by_latest_semantic_version;
use tempfile::tempdir;
#[tokio::test]
async fn default_works() -> anyhow::Result<()> {
let expected = RelayChain::Polkadot;
let temp_dir = tempdir()?;
let relay =
default(Some(RELAY_BINARY_VERSION), None, "paseo-local", temp_dir.path()).await?;
assert!(matches!(relay.binary, Binary::Source { name, source, cache }
if name == expected.binary() && source == Source::GitHub(ReleaseArchive {
owner: "r0gue-io".to_string(),
repository: "polkadot".to_string(),
tag: Some(format!("polkadot-{RELAY_BINARY_VERSION}")),
tag_pattern: Some("polkadot-{version}".into()),
prerelease: false,
version_comparator: sort_by_latest_stable_version,
fallback: FALLBACK.into(),
archive: format!("{name}-{}.tar.gz", target()?),
contents: ["polkadot", "polkadot-execute-worker", "polkadot-prepare-worker"].map(|b| ArchiveFileSpec::new(b.into(), None, true)).to_vec(),
latest: relay.binary.latest().map(|l| l.to_string()),
}).into() && cache == temp_dir.path()
));
assert_eq!(relay.workers, expected.workers());
Ok(())
}
#[tokio::test]
async fn default_with_chain_spec_generator_works() -> anyhow::Result<()> {
let runtime_version = "v1.3.3";
let temp_dir = tempdir()?;
let relay = default(None, Some(runtime_version), "paseo-local", temp_dir.path()).await?;
assert_eq!(relay.chain, "paseo-local");
let chain_spec_generator = relay.chain_spec_generator.unwrap();
assert!(matches!(chain_spec_generator, Binary::Source { name, source, cache }
if name == "paseo-chain-spec-generator" && source == Source::GitHub(ReleaseArchive {
owner: "r0gue-io".to_string(),
repository: "paseo-runtimes".to_string(),
tag: Some(runtime_version.to_string()),
tag_pattern: None,
prerelease: false,
version_comparator: sort_by_latest_semantic_version,
fallback: "v1.4.1".into(),
archive: format!("chain-spec-generator-{}.tar.gz", target()?),
contents: [ArchiveFileSpec::new("chain-spec-generator".into(), Some("paseo-chain-spec-generator".into()), true)].to_vec(),
latest: chain_spec_generator.latest().map(|l| l.to_string()),
}).into() && cache == temp_dir.path()
));
Ok(())
}
#[tokio::test]
async fn from_handles_unsupported_command() -> anyhow::Result<()> {
assert!(
matches!(from("none", None, None, "paseo-local", tempdir()?.path()).await, Err(Error::UnsupportedCommand(e))
if e == "the relay chain command is unsupported: none")
);
Ok(())
}
#[tokio::test]
async fn from_handles_local_command() -> anyhow::Result<()> {
let expected = RelayChain::Polkadot;
let temp_dir = tempdir()?;
let relay = from(
"./bin-stable2512/polkadot",
Some(RELAY_BINARY_VERSION),
None,
"paseo-local",
temp_dir.path(),
)
.await?;
assert!(matches!(relay.binary, Binary::Source { name, source, cache }
if name == expected.binary() && source == Source::GitHub(ReleaseArchive {
owner: "r0gue-io".to_string(),
repository: "polkadot".to_string(),
tag: Some(format!("polkadot-{RELAY_BINARY_VERSION}")),
tag_pattern: Some("polkadot-{version}".into()),
prerelease: false,
version_comparator: sort_by_latest_stable_version,
fallback: FALLBACK.into(),
archive: format!("{name}-{}.tar.gz", target()?),
contents: ["polkadot", "polkadot-execute-worker", "polkadot-prepare-worker"].map(|b| ArchiveFileSpec::new(b.into(), None, true)).to_vec(),
latest: relay.binary.latest().map(|l| l.to_string()),
}).into() && cache == temp_dir.path()
));
assert_eq!(relay.workers, expected.workers());
Ok(())
}
}