1#![doc = include_str!("../README.md")]
4
5pub use account_id::{parse_account, parse_h160_account};
6#[cfg(feature = "integration-tests")]
7#[allow(deprecated)]
8use assert_cmd::cargo::cargo_bin;
9pub use build::Profile;
10pub use docker::Docker;
11pub use errors::Error;
12pub use git::{Git, GitHub, Release};
13pub use helpers::{
14 get_project_name_from_path, get_relative_or_absolute_path, is_root, replace_in_file,
15};
16pub use metadata::format_type;
17pub use signer::create_signer;
18pub use sourcing::set_executable_permission;
19use std::{cmp::Ordering, net::TcpListener, ops::Deref};
20#[cfg(feature = "integration-tests")]
21use std::{ffi::OsStr, path::Path};
22pub use subxt::{Config, PolkadotConfig as DefaultConfig};
23pub use subxt_signer::sr25519::Keypair;
24pub use templates::{
25 extractor::extract_template_files,
26 frontend::{FrontendTemplate, FrontendType},
27};
28pub use test::test_project;
29
30pub mod account_id;
32pub(crate) mod api;
34pub mod build;
36#[cfg(test)]
38pub mod command_mock;
39pub mod docker;
41pub mod errors;
43pub mod git;
45pub mod helpers;
47pub mod manifest;
49pub mod metadata;
51pub mod polkadot_sdk;
53pub mod signer;
55pub mod sourcing;
57pub mod templates;
59pub mod test;
61pub mod test_env;
63
64static APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));
65
66pub trait Status {
68 fn update(&self, status: &str);
70}
71
72impl Status for () {
73 fn update(&self, _: &str) {}
75}
76
77pub fn target() -> Result<&'static str, Error> {
79 use std::env::consts::*;
80
81 if OS == "windows" {
82 return Err(Error::UnsupportedPlatform { arch: ARCH, os: OS });
83 }
84
85 match ARCH {
86 "aarch64" => {
87 return match OS {
88 "macos" => Ok("aarch64-apple-darwin"),
89 _ => Ok("aarch64-unknown-linux-gnu"),
90 };
91 },
92 "x86_64" | "x86" => {
93 return match OS {
94 "macos" => Ok("x86_64-apple-darwin"),
95 _ => Ok("x86_64-unknown-linux-gnu"),
96 };
97 },
98 &_ => {},
99 }
100 Err(Error::UnsupportedPlatform { arch: ARCH, os: OS })
101}
102
103#[cfg(feature = "integration-tests")]
114pub fn pop(
115 dir: &Path,
116 args: impl IntoIterator<Item = impl AsRef<OsStr>>,
117) -> tokio::process::Command {
118 #[allow(deprecated)]
119 let mut command = tokio::process::Command::new(cargo_bin("pop"));
120 command.current_dir(dir).args(args);
121 println!("{command:?}");
122 command
123}
124
125pub fn resolve_port(preferred_port: Option<u16>) -> u16 {
131 if let Some(port) = preferred_port &&
133 TcpListener::bind(format!("127.0.0.1:{}", port)).is_ok()
134 {
135 return port;
136 }
137
138 TcpListener::bind("127.0.0.1:0")
140 .expect("Failed to bind to an available port")
141 .local_addr()
142 .expect("Failed to retrieve local address. This should never occur.")
143 .port()
144}
145
146pub struct SortedSlice<'a, T>(&'a mut [T]);
148impl<'a, T> SortedSlice<'a, T> {
149 pub fn by(slice: &'a mut [T], f: impl FnMut(&T, &T) -> Ordering) -> Self {
155 slice.sort_by(f);
156 Self(slice)
157 }
158
159 pub fn by_key<K: Ord>(slice: &'a mut [T], f: impl FnMut(&T) -> K) -> Self {
166 slice.sort_by_key(f);
167 Self(slice)
168 }
169}
170
171impl<T> Deref for SortedSlice<'_, T> {
172 type Target = [T];
173
174 fn deref(&self) -> &Self::Target {
175 &self.0[..]
176 }
177}
178
179pub mod call {
181 pub use contract_build::Verbosity;
185 pub use contract_extrinsics::{DisplayEvents, TokenMetadata};
186 pub use ink_env::DefaultEnvironment;
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192 use anyhow::Result;
193
194 #[test]
195 fn target_works() -> Result<()> {
196 crate::command_mock::CommandMock::default().execute_sync(|| {
197 use std::{process::Command, str};
198 let output = Command::new("rustc").arg("-vV").output()?;
199 let output = str::from_utf8(&output.stdout)?;
200 let target_expected = output
201 .lines()
202 .find(|l| l.starts_with("host: "))
203 .map(|l| &l[6..])
204 .unwrap()
205 .to_string();
206 assert_eq!(target()?, target_expected);
207 Ok(())
208 })
209 }
210
211 #[test]
212 fn resolve_port_works() -> Result<()> {
213 let port = resolve_port(None);
214 let listener = TcpListener::bind(format!("127.0.0.1:{}", port));
215 assert!(listener.is_ok());
216 Ok(())
217 }
218
219 #[test]
220 fn resolve_port_skips_busy_preferred_port() -> Result<()> {
221 let listener = TcpListener::bind("127.0.0.1:0")?;
222 let busy_port = listener.local_addr()?.port();
223 let port = resolve_port(Some(busy_port));
224 assert_ne!(port, busy_port);
225 let listener = TcpListener::bind(format!("127.0.0.1:{}", port));
226 assert!(listener.is_ok());
227 Ok(())
228 }
229
230 #[test]
231 fn sorted_slice_sorts_by_function() {
232 let mut values = ["one", "two", "three"];
233 let sorted = SortedSlice::by(values.as_mut_slice(), |a, b| a.cmp(b));
234 assert_eq!(*sorted, ["one", "three", "two"]);
235 }
236
237 #[test]
238 fn sorted_slice_sorts_by_key() {
239 let mut values = ['c', 'b', 'a'];
240 let sorted = SortedSlice::by_key(values.as_mut_slice(), |v| *v as u8);
241 assert_eq!(*sorted, ['a', 'b', 'c']);
242 }
243}