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