Skip to content

Commit

Permalink
Add support for cross-compilation (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
levkk authored Nov 26, 2024
1 parent 6593235 commit 51f81be
Show file tree
Hide file tree
Showing 8 changed files with 203 additions and 22 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,11 @@ jobs:
run: |
cargo login ${CRATES_IO_TOKEN}
cargo publish || true
- name: Publish rwf-admin
working-directory: rwf-admin
env:
CRATES_IO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
run: |
cargo login ${CRATES_IO_TOKEN}
cargo publish || true
27 changes: 23 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions rwf-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rwf-cli"
version = "0.1.6"
version = "0.1.14"
edition = "2021"
license = "MIT"
description = "Rust Web Framework CLI"
Expand All @@ -10,7 +10,7 @@ readme = "README.md"

[dependencies]
clap = { version = "4.5.18", features = ["derive"] }
rwf = { path = "../rwf", version = "0.1.9" }
rwf = { path = "../rwf", version = "0.1.14" }
tokio = { version = "1", features = ["full"] }
log = "0.4"
time = "0.3"
Expand All @@ -19,3 +19,4 @@ toml = "0.8"
flate2 = "1"
tar = "0.4"
serde_json = "1"
which = "7"
103 changes: 94 additions & 9 deletions rwf-cli/src/deploy.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;

use flate2::write::GzEncoder;
use flate2::Compression;
use rwf::config::get_config;
use rwf::config::Config;
use tokio::process::Command;

Expand All @@ -16,6 +18,10 @@ pub async fn build(target: Option<String>) -> Result<bool, Box<dyn std::error::E
build.arg("build").arg("--release");

if let Some(target) = target {
if !check_target(&target)? {
return Ok(false);
};

build.arg("--target").arg(target);
}

Expand All @@ -29,11 +35,67 @@ pub async fn build(target: Option<String>) -> Result<bool, Box<dyn std::error::E
Ok(true)
}

fn check_target(target: &str) -> Result<bool, Box<dyn std::error::Error + 'static>> {
for path in [".cargo/config", ".cargo/config.toml"] {
if let Ok(mut file) = File::open(path) {
let mut config = String::new();
file.read_to_string(&mut config)?;

if let Ok(config) = toml::from_str::<toml::Value>(&config) {
if let Some(target_conf) = config.get("target") {
if let Some(config) = target_conf.get(target) {
if let Some(linker) = config.get("linker") {
let linker = linker.as_str().unwrap();
if let Ok(linker_path) = which::which(linker) {
using(format!(
"linker for target \"{}\" in {}",
target,
linker_path.display()
));
return Ok(true);
} else {
error(format!(
"target \"{}\" doesn't have the linker \"{}\" in $PATH",
target, linker
));
return Ok(false);
}
} else {
error(format!(
"target \"{}\" requires a linker configured in .cargo/config.toml",
target
));
return Ok(false);
}
} else {
error(format!(
"target \"{}\" is not configured in .cargo/config.toml",
target,
));
return Ok(false);
}
} else {
error(format!(
"target \"{}\" is not configured in .cargo/config.toml",
target,
));
return Ok(false);
}
}

break;
}
}

error(".cargo/config.toml doesn't exist or has invalid format");
Ok(false)
}

pub async fn package(
config: Option<PathBuf>,
target: Option<String>,
) -> Result<(), Box<dyn std::error::Error + 'static>> {
if !build(target).await? {
if !build(target.clone()).await? {
return Ok(());
}

Expand All @@ -42,18 +104,41 @@ pub async fn package(
let mut tar = tar::Builder::new(enc);

let info = package_info().await?;
let executable = Path::new(&info.target_dir).join("release").join(&info.name);
let executable = Path::new(&info.target_dir)
.join(if let Some(target) = &target {
Path::new(target).join("release").to_owned()
} else {
Path::new("release").to_owned()
})
.join(&info.name);

let mut paths = get_config().package.include.clone();
paths.extend(get_config().package.include_additional.clone());
let paths = paths
.into_iter()
.map(|p| p.display().to_string())
.collect::<Vec<_>>();

packaging("executable");

let bin_name = format!("{}.bin", info.name);

if paths.contains(&bin_name) {
error(format!(
"asset directory \"{}\" has the same name as the binary executable and will be overwritten in the package",
info.name
));
return Ok(());
}

packaging("binary");
tar.append_file(&info.name, &mut File::open(executable).expect("binary"))
tar.append_file(&bin_name, &mut File::open(executable).expect("binary"))
.expect("binary");

for path in ["static", "templates", "migrations"] {
let p = Path::new(path);

for path in paths {
let p = Path::new(&path);
if p.is_dir() {
packaging(path);
tar.append_dir_all(path, p)?;
packaging(&path);
tar.append_dir_all(&path, p)?;
}
}

Expand Down
24 changes: 18 additions & 6 deletions rwf-cli/src/logging.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
use rwf::colors::MaybeColorize;

pub fn written(something: impl ToString) {
eprintln!("{} {}", "written".green(), something.to_string());
eprintln!("{} {}", " Written".green().bold(), something.to_string());
}

pub fn created(something: impl ToString) {
eprintln!("{} {}", "created".green(), something.to_string());
eprintln!("{} {}", " Created".green().bold(), something.to_string());
}

pub fn error(something: impl ToString) {
eprintln!("{}: {}", "error".red(), something.to_string());
eprintln!("{}: {}", "error".red().bold(), something.to_string());
}

pub fn warning(something: impl ToString) {
eprintln!("{}: {}", "warning".yellow(), something.to_string());
eprintln!(
"{}: {}",
" Warning".yellow().bold(),
something.to_string()
);
}

pub fn removed(something: impl ToString) {
eprintln!("{} {}", "removed".red(), something.to_string());
eprintln!("{} {}", " Removed".red().bold(), something.to_string());
}

pub fn packaging(something: impl ToString) {
eprintln!("{} {}", "packaging".green(), something.to_string());
eprintln!(
"{} {}",
" Packaging".green().bold(),
something.to_string()
);
}

pub fn using(something: impl ToString) {
eprintln!(" {} {}", "Using".green().bold(), something.to_string());
}
2 changes: 1 addition & 1 deletion rwf/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rwf"
version = "0.1.13"
version = "0.1.14"
edition = "2021"
license = "MIT"
description = "Framework for building web applications in the Rust programming language"
Expand Down
15 changes: 15 additions & 0 deletions rwf/src/colors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub trait MaybeColorize {
fn red(&self) -> String;
fn purple(&self) -> String;
fn yellow(&self) -> String;
fn bold(&self) -> String;
}

impl MaybeColorize for &str {
Expand Down Expand Up @@ -50,6 +51,16 @@ impl MaybeColorize for &str {
self.to_string()
}
}

fn bold(&self) -> String {
let config = get_config();

if config.general.tty {
Colorize::bold(*self).to_string()
} else {
self.to_string()
}
}
}

impl MaybeColorize for String {
Expand All @@ -68,6 +79,10 @@ impl MaybeColorize for String {
fn yellow(&self) -> String {
MaybeColorize::yellow(&self.as_str())
}

fn bold(&self) -> String {
MaybeColorize::bold(&self.as_str())
}
}

#[cfg(test)]
Expand Down
41 changes: 41 additions & 0 deletions rwf/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ pub struct Config {
/// WebSocket connections settings.
#[serde(default = "WebsocketConfig::default")]
pub websocket: WebsocketConfig,

/// Packaging configuration.
#[serde(default = "PackageConfig::default")]
pub package: PackageConfig,
}

impl Default for Config {
Expand All @@ -77,6 +81,7 @@ impl Default for Config {
general: General::default(),
database: DatabaseConfig::default(),
websocket: WebsocketConfig::default(),
package: PackageConfig::default(),
}
.transform()
.unwrap()
Expand Down Expand Up @@ -514,3 +519,39 @@ name = "test"
}
}
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PackageConfig {
/// Paths to include into the build. Default: migrations, static, templates.
/// If overriding, don't forget to add the default paths above.
#[serde(default = "PackageConfig::default_include")]
pub include: Vec<PathBuf>,

/// Additional paths to include into the build. Paths can be absolute
/// or relative.
#[serde(default = "PackageConfig::default_include_additional")]
pub include_additional: Vec<PathBuf>,
}

impl Default for PackageConfig {
fn default() -> Self {
Self {
include: Self::default_include(),
include_additional: Self::default_include_additional(),
}
}
}

impl PackageConfig {
fn default_include() -> Vec<PathBuf> {
vec![
PathBuf::from("migrations"),
PathBuf::from("static"),
PathBuf::from("templates"),
]
}

fn default_include_additional() -> Vec<PathBuf> {
vec![]
}
}

0 comments on commit 51f81be

Please sign in to comment.