Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support moon generate #294

Merged
merged 4 commits into from
Sep 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/moon/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ pub enum MoonBuildSubcommands {
// Misc
Coverage(CoverageSubcommand),
GenerateBuildMatrix(GenerateBuildMatrix),

/// Upgrade toolchains
Upgrade(UpgradeSubcommand),
ShellCompletion(ShellCompSubCommand),
Expand Down
16 changes: 15 additions & 1 deletion crates/moon/src/cli/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@
//
// For inquiries, you can contact us via e-mail at [email protected].

mod format_and_diff;
use std::path::PathBuf;

pub mod embed;
pub mod format_and_diff;

use embed::*;
use format_and_diff::*;

#[derive(Debug, clap::Parser)]
Expand All @@ -29,10 +33,20 @@ pub struct ToolSubcommand {
#[derive(Debug, clap::Parser)]
pub enum ToolSubcommands {
FormatAndDiff(FormatAndDiffSubcommand),
Embed(Embed),
}

#[derive(Debug, clap::Parser)]
pub struct FormatAndWriteSubcommand {
#[clap(long)]
old: PathBuf,
#[clap(long)]
new: PathBuf,
}

pub fn run_tool(cmd: ToolSubcommand) -> anyhow::Result<i32> {
match cmd.subcommand {
ToolSubcommands::FormatAndDiff(subcmd) => run_format_and_diff(subcmd),
ToolSubcommands::Embed(subcmd) => run_embed(subcmd),
}
}
86 changes: 86 additions & 0 deletions crates/moon/src/cli/tool/embed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// moon: The build system and package manager for MoonBit.
// Copyright (C) 2024 International Digital Economy Academy
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// For inquiries, you can contact us via e-mail at [email protected].

use std::path::PathBuf;

use anyhow::Context;

#[derive(Debug, clap::Parser)]
pub struct Embed {
#[clap(long, conflicts_with = "text")]
binary: bool,
#[clap(long, conflicts_with = "binary")]
text: bool,
#[clap(long, short)]
input: PathBuf,
#[clap(long, short)]
output: PathBuf,
#[clap(long)]
name: Option<String>,
#[clap(long)]
timestamp: bool,
}

pub fn run_embed_text(cmd: Embed) -> anyhow::Result<i32> {
let input = std::fs::read_to_string(&cmd.input)?;
let name = cmd.name.unwrap_or_else(|| "resource".to_string());
let mut content = format!(
"// Generated by `moon tool embed --text`{}, do not edit.\n\n\
let {} : String =\n",
if cmd.timestamp {
format!(" on {}", chrono::Local::now().format("%Y-%m-%d %H:%M:%S"))
} else {
String::new()
},
name
);
for line in input.split('\n') {
content.push_str(&format!(" #|{}\n", line));
}
std::fs::write(cmd.output, content).context("write output file")?;
Ok(0)
}

pub fn run_embed_bin(cmd: Embed) -> anyhow::Result<i32> {
let input = std::fs::read(&cmd.input)?;
let name = cmd.name.unwrap_or_else(|| "resource".to_string());
let mut content = format!(
"// Generated by `moon tool embed --binary`{}, do not edit.\n\n\
let {} : Bytes = b\"",
if cmd.timestamp {
format!(" on {}", chrono::Local::now().format("%Y-%m-%d %H:%M:%S"))
} else {
String::new()
},
name
);
for byte in input.iter() {
content.push_str(&format!("\\x{:02x}", byte));
}
content.push_str("\"\n");
std::fs::write(cmd.output, content).context("write output file")?;
Ok(0)
}

pub fn run_embed(cmd: Embed) -> anyhow::Result<i32> {
if cmd.binary {
run_embed_bin(cmd)
} else {
run_embed_text(cmd)
}
}
2 changes: 2 additions & 0 deletions crates/moon/tests/test_cases/pre_build.in/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target/
.mooncakes/
1 change: 1 addition & 0 deletions crates/moon/tests/test_cases/pre_build.in/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# username/hello
10 changes: 10 additions & 0 deletions crates/moon/tests/test_cases/pre_build.in/moon.mod.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "username/hello",
"version": "0.1.0",
"readme": "README.md",
"repository": "",
"license": "",
"keywords": [],
"description": "",
"source": "src"
}
26 changes: 26 additions & 0 deletions crates/moon/tests/test_cases/pre_build.in/moon.test.ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
$ moon check

Executed 3 pre-build tasks, now up to date
Finished. moon: ran 2 tasks, now up to date

$ xcat src/lib/a.mbt
// Generated by `moon tool embed --text` do not edit.

let resource : String =
#|hello,
#|world
#|

$ xcat src/lib/b.mbt
// Generated by `moon tool embed --binary` do not edit.

let _b : Bytes = b"/x6d/x6f/x6f/x6e/x0a/x67/x65/x6e/x65/x72/x61/x74/x65/x0a"

$ xcat src/lib/c.mbt
// Generated by `moon tool embed --text` do not edit.

let _c : String =
#|hello,
#|world
#|

2 changes: 2 additions & 0 deletions crates/moon/tests/test_cases/pre_build.in/src/lib/a.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
hello,
world
2 changes: 2 additions & 0 deletions crates/moon/tests/test_cases/pre_build.in/src/lib/b.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
moon
generate
2 changes: 2 additions & 0 deletions crates/moon/tests/test_cases/pre_build.in/src/lib/c.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
hello,
world
3 changes: 3 additions & 0 deletions crates/moon/tests/test_cases/pre_build.in/src/lib/hello.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub fn hello() -> String {
"Hello, world!"
}
19 changes: 19 additions & 0 deletions crates/moon/tests/test_cases/pre_build.in/src/lib/moon.pkg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"pre-build": [
{
"input": "a.txt",
"output": "a.mbt",
"command": ":embed --text -i ${input} -o ${output}"
},
{
"input": ["b.txt"],
"output": "b.mbt",
"command": ":embed --binary -i ${input} -o ${output} --name _b"
},
{
"input": "c.txt",
"output": "c.mbt",
"command": ":embed --text -i ${input} -o ${output} --name _c"
}
]
}
3 changes: 3 additions & 0 deletions crates/moon/tests/test_cases/pre_build.in/src/main/main.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main {
println(@lib.hello())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"is-main": true,
"import": [
"username/hello/lib"
]
}
2 changes: 2 additions & 0 deletions crates/moonbuild/src/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ pub fn f() -> Unit {{
warn_list: None,
alert_list: None,
targets: None,
pre_build: None,
};
moonutil::common::write_package_json_to_file(&pkg, &moon_pkg).unwrap();
}
Expand Down Expand Up @@ -190,6 +191,7 @@ pub fn write(config: &Config, base_dir: &Path) {
warn_list: None,
alert_list: None,
targets: None,
pre_build: None,
};

moonutil::common::write_package_json_to_file(&pkg, &base_dir.join("main").join(MOON_PKG_JSON))
Expand Down
87 changes: 87 additions & 0 deletions crates/moonbuild/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,59 @@ fn render_result(result: Option<usize>, quiet: bool, mode: &str) -> anyhow::Resu
}
}

pub fn n2_simple_run_interface(
state: n2::load::State,
moonbuild_opt: &MoonbuildOpt,
) -> anyhow::Result<Option<usize>> {
let logger = Arc::new(Mutex::new(vec![]));
let use_fancy = terminal::use_fancy();

let catcher = Arc::clone(&logger);
let output_json = moonbuild_opt.output_json;
let render_and_catch = move |output: &str| {
output
.split('\n')
.filter(|it| !it.is_empty())
.for_each(|content| {
catcher.lock().unwrap().push(content.to_owned());
if output_json {
println!("{content}");
} else {
moonutil::render::MooncDiagnostic::render(content, use_fancy);
}
});
};

// TODO: generate build graph for pre_build?

let mut progress = create_progress_console(Some(Box::new(render_and_catch)));
let options = work::Options {
parallelism: default_parallelism()?,
failures_left: Some(10),
explain: false,
adopt: false,
};
let mut work = work::Work::new(
state.graph,
state.hashes,
state.db,
&options,
progress.as_mut(),
state.pools,
);

if !state.default.is_empty() {
for target in state.default {
work.want_file(target)?;
}
} else {
return Ok(Some(0));
}

let res = trace::scope("work.run", || work.run())?;
Ok(res)
}

pub fn n2_run_interface(
state: n2::load::State,
moonbuild_opt: &MoonbuildOpt,
Expand Down Expand Up @@ -231,11 +284,39 @@ fn vis_build_graph(state: &State, moonbuild_opt: &MoonbuildOpt) {
eprintln!("generated build graph: {}", path.display());
}

fn run_moon_generate(moonbuild_opt: &MoonbuildOpt, module: &ModuleDB) -> anyhow::Result<i32> {
let generate_state = crate::generate::load_moon_generate(moonbuild_opt, module)?;
let generate_result = n2_simple_run_interface(generate_state, moonbuild_opt)?;
render_generate_result(generate_result, moonbuild_opt.quiet)?;
Ok(0)
}

fn render_generate_result(result: Option<usize>, quiet: bool) -> anyhow::Result<i32> {
match result {
None => {
anyhow::bail!(format!("failed when execute generate"));
}
Some(0) => Ok(0),
Some(n) => {
if !quiet {
eprintln!(
"Executed {} pre-build task{}, now up to date",
n,
if n == 1 { "" } else { "s" }
);
}
Ok(0)
}
}
}

pub fn run_check(
moonc_opt: &MooncOpt,
moonbuild_opt: &MoonbuildOpt,
module: &ModuleDB,
) -> anyhow::Result<i32> {
run_moon_generate(moonbuild_opt, module)?;

let state = trace::scope("moonbit::check::read", || {
crate::check::normal::load_moon_proj(module, moonc_opt, moonbuild_opt)
})?;
Expand All @@ -256,6 +337,8 @@ pub fn run_build(
moonbuild_opt: &MoonbuildOpt,
module: &ModuleDB,
) -> anyhow::Result<i32> {
run_moon_generate(moonbuild_opt, module)?;

let state = trace::scope("moonbit::build::read", || {
crate::build::load_moon_proj(module, moonc_opt, moonbuild_opt)
})?;
Expand Down Expand Up @@ -455,6 +538,8 @@ pub fn run_test(
auto_update: bool,
module: ModuleDB,
) -> anyhow::Result<Vec<Result<TestStatistics, TestFailedStatus>>> {
run_moon_generate(&moonbuild_opt, &module)?;

let moonc_opt = Arc::new(moonc_opt);
let moonbuild_opt = Arc::new(moonbuild_opt);
let module = Arc::new(module);
Expand Down Expand Up @@ -928,6 +1013,8 @@ pub fn run_bundle(
moonbuild_opt: &MoonbuildOpt,
moonc_opt: &MooncOpt,
) -> anyhow::Result<i32> {
run_moon_generate(moonbuild_opt, module)?;

let state = crate::bundle::load_moon_proj(module, moonc_opt, moonbuild_opt)?;
let result = n2_run_interface(state, moonbuild_opt)?;
match result {
Expand Down
Loading
Loading