diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c1e9e4..766c32b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,3 +30,16 @@ jobs: - uses: actions/checkout@v1 - run: cargo clippy + cross-testing-arm64-linux: + name: Cross testing for the aarch64-unknown-linux-gnu target + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Install cross + run: cargo install cross + - name: Build the cross Dockerfile + run: docker build -t parsec-cross . + - name: Cross-compile with cross + run: cross build --target aarch64-unknown-linux-gnu --verbose + - name: Execute the unit tests with cross + run: cross test --target aarch64-unknown-linux-gnu --verbose diff --git a/Cross.toml b/Cross.toml new file mode 100644 index 0000000..d95d410 --- /dev/null +++ b/Cross.toml @@ -0,0 +1,4 @@ +# cross configuration file to use the Dockerfile + +[target.aarch64-unknown-linux-gnu] +image = "parsec-cross" diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..32b9d65 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +# This Dockerfile is used by cross for cross-compilation and cross-testing of +# PARSEC. + +FROM rustembedded/cross:aarch64-unknown-linux-gnu-0.1.16 + +RUN apt-get update && \ + # wget is needed in the build script to download the operations. + apt-get install -y wget diff --git a/build.rs b/build.rs index c96f099..0f76d34 100644 --- a/build.rs +++ b/build.rs @@ -12,39 +12,21 @@ // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use std::fs::{read_dir, OpenOptions}; -use std::io::{Result, Write}; +use std::env; +use std::fs::read_dir; +use std::io::Result; use std::path::Path; -use std::process::{Command, Output}; +use std::process::Command; -const PROTO_FOLDER: &str = "target/parsec-operations/protobuf"; -const PROTO_OUT_DIR: &str = "src/operations_protobuf/generated_ops"; const PARSEC_OPERATIONS_VERSION: &str = "0.2.0"; -// TODO: handle OsStrings more carefully, as .into_string() might fail - -fn generate_mod_file() -> Result<()> { - let dir_entries = read_dir(Path::new(PROTO_FOLDER))?; - let mod_file_path = format!("{}/mod.rs", PROTO_OUT_DIR); - let mut mod_file = OpenOptions::new() - .write(true) - .truncate(true) - .create(true) - .open(&mod_file_path)?; - dir_entries.for_each(|file| { - let filename = file.unwrap().file_name().into_string().unwrap(); - if filename.ends_with(".proto") { - writeln!(&mut mod_file, "pub mod {};", filename.replace(".proto", "")).unwrap(); - } - }); - - mod_file.flush()?; - - Ok(()) -} - fn generate_proto_sources() -> Result<()> { - let dir_entries = read_dir(Path::new(PROTO_FOLDER))?; + let path = format!( + "{}/parsec-operations-{}/protobuf", + env::var("OUT_DIR").unwrap(), + PARSEC_OPERATIONS_VERSION + ); + let dir_entries = read_dir(Path::new(&path))?; let files: Vec = dir_entries .map(|protos_file| { protos_file @@ -57,31 +39,48 @@ fn generate_proto_sources() -> Result<()> { .filter(|string| string.ends_with(".proto")) .collect(); let files_slices: Vec<&str> = files.iter().map(|file| &file[..]).collect(); - let mut prost_config = prost_build::Config::new(); - prost_config.out_dir(Path::new("./src/operations_protobuf/generated_ops")); - prost_config - .compile_protos(&files_slices, &[PROTO_FOLDER]) - .expect("failed to generate protos"); + prost_build::compile_protos(&files_slices, &[&path]).expect("failed to generate protos"); Ok(()) } -fn get_protobuf_files() -> Result { - // TODO: Downloading a release file and decompressing it might be faster here. +fn get_protobuf_files() { // TODO: Use semantic versioning to get the newest versions. - Command::new("git") - .arg("clone") - .arg("https://github.com/parallaxsecond/parsec-operations.git") - .arg("-b") - .arg(PARSEC_OPERATIONS_VERSION) - .arg("target/parsec-operations") - .output() + if !Command::new("wget") + .arg(format!( + "https://github.com/parallaxsecond/parsec-operations/archive/{}.tar.gz", + PARSEC_OPERATIONS_VERSION + )) + .arg(format!( + "--directory-prefix={}", + env::var("OUT_DIR").unwrap() + )) + .status() + .expect("wget command failed.") + .success() + { + panic!("wget command returned an error status."); + } + + // Gets extracted as parsec-operations-PARSEC_OPERATIONS_VERSION directory. + if !Command::new("tar") + .arg("xf") + .arg(format!( + "{}/{}.tar.gz", + env::var("OUT_DIR").unwrap(), + PARSEC_OPERATIONS_VERSION + )) + .arg("--directory") + .arg(env::var("OUT_DIR").unwrap()) + .status() + .expect("tar command failed.") + .success() + { + panic!("tar command returned an error status."); + } } fn main() { - get_protobuf_files().expect("Failed to download the protobuf files."); - - generate_mod_file().expect("Failed to generate a mod file for the proto dir."); - + get_protobuf_files(); generate_proto_sources().expect("Failed to generate protobuf source code from proto files."); } diff --git a/src/operations_protobuf/mod.rs b/src/operations_protobuf/mod.rs index 3e3535d..2672dd6 100644 --- a/src/operations_protobuf/mod.rs +++ b/src/operations_protobuf/mod.rs @@ -27,7 +27,28 @@ mod convert_list_providers; mod convert_list_opcodes; #[rustfmt::skip] -mod generated_ops; +mod generated_ops { + // Include the Rust generated file in its own module. + macro_rules! include_protobuf_as_module { + ($name:ident) => { + pub mod $name { + // The generated Rust file is in OUT_DIR, named $name.rs + include!(concat!(env!("OUT_DIR"), "/", stringify!($name), ".rs")); + } + }; + } + + include_protobuf_as_module!(asym_sign); + include_protobuf_as_module!(asym_verify); + include_protobuf_as_module!(create_key); + include_protobuf_as_module!(destroy_key); + include_protobuf_as_module!(export_public_key); + include_protobuf_as_module!(import_key); + include_protobuf_as_module!(list_opcodes); + include_protobuf_as_module!(list_providers); + include_protobuf_as_module!(ping); + include_protobuf_as_module!(key_attributes); +} use crate::operations::{Convert, NativeOperation, NativeResult}; use crate::requests::{