2025-07-26 14:18:30 +02:00
|
|
|
use anyhow::{Context, Result};
|
|
|
|
|
use clap::{Parser, Subcommand};
|
|
|
|
|
use std::fs::{self, File};
|
|
|
|
|
use std::io::Write;
|
2025-07-26 17:49:56 +02:00
|
|
|
use std::path::{Path, PathBuf};
|
2025-07-26 14:18:30 +02:00
|
|
|
use std::process::Command;
|
|
|
|
|
|
|
|
|
|
// Constants
|
|
|
|
|
const TEST_BASE_DIR: &str = "/tmp/pkg6_test";
|
|
|
|
|
const PROTOTYPE_DIR: &str = "/tmp/pkg6_test/prototype";
|
|
|
|
|
const MANIFEST_DIR: &str = "/tmp/pkg6_test/manifests";
|
2025-07-26 17:49:56 +02:00
|
|
|
const E2E_TEST_BIN_DIR: &str = "/tmp/pkg6_test/bin";
|
2025-07-26 14:18:30 +02:00
|
|
|
|
|
|
|
|
#[derive(Parser)]
|
|
|
|
|
#[command(author, version, about, long_about = None)]
|
|
|
|
|
struct Cli {
|
|
|
|
|
#[command(subcommand)]
|
|
|
|
|
command: Commands,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Subcommand)]
|
|
|
|
|
enum Commands {
|
|
|
|
|
/// Set up the test environment for repository tests
|
|
|
|
|
SetupTestEnv,
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
/// Build the project
|
|
|
|
|
Build {
|
|
|
|
|
/// Build with release optimizations
|
|
|
|
|
#[arg(short, long)]
|
|
|
|
|
release: bool,
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
/// Specific crate to build
|
|
|
|
|
#[arg(short, long)]
|
|
|
|
|
package: Option<String>,
|
|
|
|
|
},
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
/// Run tests
|
|
|
|
|
Test {
|
|
|
|
|
/// Run tests with release optimizations
|
|
|
|
|
#[arg(short, long)]
|
|
|
|
|
release: bool,
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
/// Specific crate to test
|
|
|
|
|
#[arg(short, long)]
|
|
|
|
|
package: Option<String>,
|
|
|
|
|
},
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
/// Build binaries for end-to-end tests
|
|
|
|
|
BuildE2E,
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
/// Run end-to-end tests using pre-built binaries
|
|
|
|
|
RunE2E {
|
|
|
|
|
/// Specific test to run (runs all e2e tests if not specified)
|
|
|
|
|
#[arg(short, long)]
|
|
|
|
|
test: Option<String>,
|
|
|
|
|
},
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
/// Format code
|
|
|
|
|
Fmt,
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
/// Run clippy
|
|
|
|
|
Clippy,
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
/// Clean build artifacts
|
|
|
|
|
Clean,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn main() -> Result<()> {
|
|
|
|
|
let cli = Cli::parse();
|
|
|
|
|
|
|
|
|
|
match &cli.command {
|
|
|
|
|
Commands::SetupTestEnv => setup_test_env(),
|
|
|
|
|
Commands::Build { release, package } => build(release, package),
|
|
|
|
|
Commands::Test { release, package } => test(release, package),
|
2025-07-26 17:49:56 +02:00
|
|
|
Commands::BuildE2E => build_e2e(),
|
|
|
|
|
Commands::RunE2E { test } => run_e2e(test),
|
2025-07-26 14:18:30 +02:00
|
|
|
Commands::Fmt => fmt(),
|
|
|
|
|
Commands::Clippy => clippy(),
|
|
|
|
|
Commands::Clean => clean(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Set up the test environment for repository tests
|
|
|
|
|
fn setup_test_env() -> Result<()> {
|
|
|
|
|
println!("Setting up test environment...");
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
// Clean up any existing test directories except the bin directory
|
2025-07-26 14:18:30 +02:00
|
|
|
if Path::new(TEST_BASE_DIR).exists() {
|
|
|
|
|
println!("Cleaning up existing test directory...");
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
// Remove subdirectories individually, preserving the bin directory
|
|
|
|
|
let entries = fs::read_dir(TEST_BASE_DIR).context("Failed to read test directory")?;
|
|
|
|
|
for entry in entries {
|
|
|
|
|
let entry = entry.context("Failed to read directory entry")?;
|
|
|
|
|
let path = entry.path();
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
// Skip the bin directory
|
|
|
|
|
if path.is_dir() && path.file_name().unwrap_or_default() != "bin" {
|
2025-07-27 15:22:49 +02:00
|
|
|
fs::remove_dir_all(&path)
|
|
|
|
|
.context(format!("Failed to remove directory: {:?}", path))?;
|
2025-07-26 17:49:56 +02:00
|
|
|
} else if path.is_file() {
|
|
|
|
|
fs::remove_file(&path).context(format!("Failed to remove file: {:?}", path))?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Create the base directory if it doesn't exist
|
|
|
|
|
fs::create_dir_all(TEST_BASE_DIR).context("Failed to create test base directory")?;
|
2025-07-26 14:18:30 +02:00
|
|
|
}
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
// Create test directories
|
|
|
|
|
println!("Creating test directories...");
|
|
|
|
|
fs::create_dir_all(PROTOTYPE_DIR).context("Failed to create prototype directory")?;
|
|
|
|
|
fs::create_dir_all(MANIFEST_DIR).context("Failed to create manifest directory")?;
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
// Compile the applications
|
|
|
|
|
println!("Compiling applications...");
|
|
|
|
|
Command::new("cargo")
|
|
|
|
|
.arg("build")
|
|
|
|
|
.status()
|
|
|
|
|
.context("Failed to compile applications")?;
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
// Create a simple prototype directory structure with some files
|
|
|
|
|
println!("Creating prototype directory structure...");
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
// Create some directories
|
2025-07-27 15:22:49 +02:00
|
|
|
fs::create_dir_all(format!("{}/usr/bin", PROTOTYPE_DIR))
|
|
|
|
|
.context("Failed to create usr/bin directory")?;
|
|
|
|
|
fs::create_dir_all(format!("{}/usr/share/doc/example", PROTOTYPE_DIR))
|
|
|
|
|
.context("Failed to create usr/share/doc/example directory")?;
|
|
|
|
|
fs::create_dir_all(format!("{}/etc/config", PROTOTYPE_DIR))
|
|
|
|
|
.context("Failed to create etc/config directory")?;
|
|
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
// Create some files
|
|
|
|
|
let hello_script = "#!/bin/sh\necho 'Hello, World!'";
|
2025-07-27 15:22:49 +02:00
|
|
|
let mut hello_file = File::create(format!("{}/usr/bin/hello", PROTOTYPE_DIR))
|
|
|
|
|
.context("Failed to create hello script")?;
|
|
|
|
|
hello_file
|
|
|
|
|
.write_all(hello_script.as_bytes())
|
|
|
|
|
.context("Failed to write hello script")?;
|
|
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
// Make the script executable
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
|
{
|
|
|
|
|
use std::os::unix::fs::PermissionsExt;
|
|
|
|
|
let mut perms = fs::metadata(format!("{}/usr/bin/hello", PROTOTYPE_DIR))
|
|
|
|
|
.context("Failed to get hello script metadata")?
|
|
|
|
|
.permissions();
|
|
|
|
|
perms.set_mode(0o755);
|
|
|
|
|
fs::set_permissions(format!("{}/usr/bin/hello", PROTOTYPE_DIR), perms)
|
|
|
|
|
.context("Failed to set hello script permissions")?;
|
|
|
|
|
}
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
let readme_content = "This is an example document.";
|
2025-07-27 15:22:49 +02:00
|
|
|
let mut readme_file = File::create(format!(
|
|
|
|
|
"{}/usr/share/doc/example/README.txt",
|
|
|
|
|
PROTOTYPE_DIR
|
|
|
|
|
))
|
|
|
|
|
.context("Failed to create README.txt")?;
|
|
|
|
|
readme_file
|
|
|
|
|
.write_all(readme_content.as_bytes())
|
|
|
|
|
.context("Failed to write README.txt")?;
|
|
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
let config_content = "# Example configuration file\nvalue=42";
|
|
|
|
|
let mut config_file = File::create(format!("{}/etc/config/example.conf", PROTOTYPE_DIR))
|
|
|
|
|
.context("Failed to create example.conf")?;
|
2025-07-27 15:22:49 +02:00
|
|
|
config_file
|
|
|
|
|
.write_all(config_content.as_bytes())
|
|
|
|
|
.context("Failed to write example.conf")?;
|
|
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
// Create a simple manifest
|
|
|
|
|
println!("Creating package manifest...");
|
|
|
|
|
let example_manifest = r#"set name=pkg.fmri value=pkg://test/example@1.0.0
|
|
|
|
|
set name=pkg.summary value="Example package for testing"
|
|
|
|
|
set name=pkg.description value="This is an example package used for testing the repository implementation."
|
|
|
|
|
set name=info.classification value="org.opensolaris.category.2008:System/Core"
|
|
|
|
|
set name=variant.arch value=i386 value=sparc
|
|
|
|
|
file path=usr/bin/hello mode=0755 owner=root group=bin
|
|
|
|
|
file path=usr/share/doc/example/README.txt mode=0644 owner=root group=bin
|
|
|
|
|
file path=etc/config/example.conf mode=0644 owner=root group=bin preserve=true
|
|
|
|
|
dir path=usr/bin mode=0755 owner=root group=bin
|
|
|
|
|
dir path=usr/share/doc/example mode=0755 owner=root group=bin
|
|
|
|
|
dir path=etc/config mode=0755 owner=root group=sys
|
|
|
|
|
"#;
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
let mut example_file = File::create(format!("{}/example.p5m", MANIFEST_DIR))
|
|
|
|
|
.context("Failed to create example.p5m")?;
|
2025-07-27 15:22:49 +02:00
|
|
|
example_file
|
|
|
|
|
.write_all(example_manifest.as_bytes())
|
|
|
|
|
.context("Failed to write example.p5m")?;
|
|
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
// Create a second manifest for testing multiple packages
|
|
|
|
|
let example2_manifest = r#"set name=pkg.fmri value=pkg://test/example2@1.0.0
|
|
|
|
|
set name=pkg.summary value="Second example package for testing"
|
|
|
|
|
set name=pkg.description value="This is a second example package used for testing the repository implementation."
|
|
|
|
|
set name=info.classification value="org.opensolaris.category.2008:System/Core"
|
|
|
|
|
set name=variant.arch value=i386 value=sparc
|
|
|
|
|
file path=usr/bin/hello mode=0755 owner=root group=bin
|
|
|
|
|
file path=usr/share/doc/example/README.txt mode=0644 owner=root group=bin
|
|
|
|
|
dir path=usr/bin mode=0755 owner=root group=bin
|
|
|
|
|
dir path=usr/share/doc/example mode=0755 owner=root group=bin
|
|
|
|
|
"#;
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
let mut example2_file = File::create(format!("{}/example2.p5m", MANIFEST_DIR))
|
|
|
|
|
.context("Failed to create example2.p5m")?;
|
2025-07-27 15:22:49 +02:00
|
|
|
example2_file
|
|
|
|
|
.write_all(example2_manifest.as_bytes())
|
|
|
|
|
.context("Failed to write example2.p5m")?;
|
|
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
println!("Test environment setup complete!");
|
|
|
|
|
println!("Prototype directory: {}", PROTOTYPE_DIR);
|
|
|
|
|
println!("Manifest directory: {}", MANIFEST_DIR);
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Build the project
|
|
|
|
|
fn build(release: &bool, package: &Option<String>) -> Result<()> {
|
|
|
|
|
let mut cmd = Command::new("cargo");
|
|
|
|
|
cmd.arg("build");
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
if *release {
|
|
|
|
|
cmd.arg("--release");
|
|
|
|
|
}
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
if let Some(pkg) = package {
|
|
|
|
|
cmd.args(["--package", pkg]);
|
|
|
|
|
}
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
cmd.status().context("Failed to build project")?;
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Run tests
|
|
|
|
|
fn test(release: &bool, package: &Option<String>) -> Result<()> {
|
|
|
|
|
let mut cmd = Command::new("cargo");
|
|
|
|
|
cmd.arg("test");
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
if *release {
|
|
|
|
|
cmd.arg("--release");
|
|
|
|
|
}
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
if let Some(pkg) = package {
|
|
|
|
|
cmd.args(["--package", pkg]);
|
|
|
|
|
}
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
cmd.status().context("Failed to run tests")?;
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Format code
|
|
|
|
|
fn fmt() -> Result<()> {
|
|
|
|
|
Command::new("cargo")
|
|
|
|
|
.arg("fmt")
|
|
|
|
|
.status()
|
|
|
|
|
.context("Failed to format code")?;
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Run clippy
|
|
|
|
|
fn clippy() -> Result<()> {
|
|
|
|
|
Command::new("cargo")
|
2025-07-27 15:22:49 +02:00
|
|
|
.args([
|
|
|
|
|
"clippy",
|
|
|
|
|
"--all-targets",
|
|
|
|
|
"--all-features",
|
|
|
|
|
])
|
2025-07-26 14:18:30 +02:00
|
|
|
.status()
|
|
|
|
|
.context("Failed to run clippy")?;
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Clean build artifacts
|
|
|
|
|
fn clean() -> Result<()> {
|
|
|
|
|
Command::new("cargo")
|
|
|
|
|
.arg("clean")
|
|
|
|
|
.status()
|
|
|
|
|
.context("Failed to clean build artifacts")?;
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Build binaries for end-to-end tests
|
|
|
|
|
fn build_e2e() -> Result<()> {
|
|
|
|
|
println!("Building binaries for end-to-end tests...");
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
// Create the bin directory if it doesn't exist
|
|
|
|
|
fs::create_dir_all(E2E_TEST_BIN_DIR).context("Failed to create bin directory")?;
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
// Build pkg6repo in release mode
|
|
|
|
|
println!("Building pkg6repo...");
|
|
|
|
|
Command::new("cargo")
|
|
|
|
|
.args(["build", "--release", "--package", "pkg6repo"])
|
|
|
|
|
.status()
|
|
|
|
|
.context("Failed to build pkg6repo")?;
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2026-01-18 14:30:05 +01:00
|
|
|
// Build pkg6 in release mode
|
|
|
|
|
println!("Building pkg6...");
|
2025-07-26 17:49:56 +02:00
|
|
|
Command::new("cargo")
|
2026-01-18 14:30:05 +01:00
|
|
|
.args(["build", "--release", "--package", "pkg6"])
|
2025-07-26 17:49:56 +02:00
|
|
|
.status()
|
2026-01-18 14:30:05 +01:00
|
|
|
.context("Failed to build pkg6")?;
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
// Copy the binaries to the bin directory
|
|
|
|
|
let target_dir = PathBuf::from("target/release");
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
println!("Copying binaries to test directory...");
|
|
|
|
|
fs::copy(
|
|
|
|
|
target_dir.join("pkg6repo"),
|
|
|
|
|
PathBuf::from(E2E_TEST_BIN_DIR).join("pkg6repo"),
|
|
|
|
|
)
|
|
|
|
|
.context("Failed to copy pkg6repo binary")?;
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
fs::copy(
|
2026-01-18 14:30:05 +01:00
|
|
|
target_dir.join("pkg6"),
|
|
|
|
|
PathBuf::from(E2E_TEST_BIN_DIR).join("pkg6"),
|
2025-07-26 17:49:56 +02:00
|
|
|
)
|
2026-01-18 14:30:05 +01:00
|
|
|
.context("Failed to copy pkg6 binary")?;
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
println!("End-to-end test binaries built successfully!");
|
|
|
|
|
println!("Binaries are located at: {}", E2E_TEST_BIN_DIR);
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Run end-to-end tests using pre-built binaries
|
|
|
|
|
fn run_e2e(test: &Option<String>) -> Result<()> {
|
|
|
|
|
println!("Running end-to-end tests...");
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
// Check if the binaries exist
|
|
|
|
|
let pkg6repo_bin = PathBuf::from(E2E_TEST_BIN_DIR).join("pkg6repo");
|
2026-01-18 14:30:05 +01:00
|
|
|
let pkg6_bin = PathBuf::from(E2E_TEST_BIN_DIR).join("pkg6");
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2026-01-18 14:30:05 +01:00
|
|
|
if !pkg6repo_bin.exists() || !pkg6_bin.exists() {
|
2025-07-26 17:49:56 +02:00
|
|
|
println!("Pre-built binaries not found. Building them first...");
|
|
|
|
|
build_e2e()?;
|
|
|
|
|
}
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
// Set up the test environment
|
|
|
|
|
setup_test_env()?;
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
// Run the tests
|
|
|
|
|
let mut cmd = Command::new("cargo");
|
|
|
|
|
cmd.arg("test");
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
if let Some(test_name) = test {
|
|
|
|
|
cmd.args(["--package", "pkg6repo", "--test", "e2e_tests", test_name]);
|
|
|
|
|
} else {
|
|
|
|
|
cmd.args(["--package", "pkg6repo", "--test", "e2e_tests"]);
|
|
|
|
|
}
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
// Set the environment variable for the test binaries
|
|
|
|
|
cmd.env("PKG6_TEST_BIN_DIR", E2E_TEST_BIN_DIR);
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
cmd.status().context("Failed to run end-to-end tests")?;
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 17:49:56 +02:00
|
|
|
println!("End-to-end tests completed!");
|
2025-07-27 15:22:49 +02:00
|
|
|
|
2025-07-26 14:18:30 +02:00
|
|
|
Ok(())
|
2025-07-27 15:22:49 +02:00
|
|
|
}
|