Skip to content

Commit

Permalink
Merge pull request #64 from scoville/fixes-v2
Browse files Browse the repository at this point in the history
Make the pyaco generator run for the ATS typescript repo
  • Loading branch information
vtrofin authored Apr 24, 2023
2 parents 188ddc2 + f550eba commit 5ac3ef8
Show file tree
Hide file tree
Showing 14 changed files with 330 additions and 244 deletions.
400 changes: 226 additions & 174 deletions Cargo.lock

Large diffs are not rendered by default.

25 changes: 19 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
# tells make that a target is not an actual file
# always considered out-of-date and executed every time the target is explicitly requested
.PHONY: setup release clean clean-all

setup:
cargo install cross
npm install -g yarn
# Start setup
@if ! command -v cross &> /dev/null; then \
cargo install cross --git https://github.com/cross-rs/cross; \
fi
yarn
# Setup complete

release: setup
# Make release directory
Expand All @@ -11,25 +17,32 @@ release: setup
# Build node native binary for unsupported platforms
yarn release-pyaco-node

# Add targets for cross compilation
rustup target add x86_64-apple-darwin

# Build binaries for all mainstream platforms
cross build --release --target x86_64-pc-windows-gnu
cargo build --release --target aarch64-apple-darwin
cargo build --release --target x86_64-apple-darwin
cross build --release --target x86_64-unknown-linux-gnu
cross build --release --target x86_64-pc-windows-gnu

# Create folders for the binary
mkdir -p ./builds/pyaco-win64
mkdir -p ./builds/pyaco-macos-arm64
mkdir -p ./builds/pyaco-macos
mkdir -p ./builds/pyaco-linux
mkdir -p ./builds/pyaco-win64

# Copy the binaries into the right folder
cp ./target/x86_64-pc-windows-gnu/release/pyaco.exe ./builds/pyaco-win64/pyaco.exe
cp ./target/aarch64-apple-darwin/release/pyaco ./builds/pyaco-macos-arm64/pyaco
cp ./target/x86_64-apple-darwin/release/pyaco ./builds/pyaco-macos/pyaco
cp ./target/x86_64-unknown-linux-gnu/release/pyaco ./builds/pyaco-linux/pyaco
cp ./target/x86_64-pc-windows-gnu/release/pyaco.exe ./builds/pyaco-win64/pyaco.exe

# Tar binaries (except for the native node one)
tar -C ./builds -czvf ./releases/pyaco-win64.tar.gz pyaco-win64
tar -C ./builds -czvf ./releases/pyaco-macos-arm64.tar.gz pyaco-macos-arm64
tar -C ./builds -czvf ./releases/pyaco-macos.tar.gz pyaco-macos
tar -C ./builds -czvf ./releases/pyaco-linux.tar.gz pyaco-linux
tar -C ./builds -czvf ./releases/pyaco-win64.tar.gz pyaco-win64

# Cleanup builds folder
rm -fr ./builds
Expand Down
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,29 @@ Not all platforms are currently supported officially (MacOS M1 / AArch64 for ins

Nonetheless, for the time being and in order to make this tool as easy as possible to use, when a platform is not recognized the node native "binary" plus an alternative CLI facade in Node.js will be used instead. So all platforms that support Node should work now. Notice that a small performance degradation is to be expected.

Check the `/npm` folder and the `package.json` at the main path to get a better undertanding of how the package is being installed and run. Long story short, it uses [Neon](https://neon-bindings.com/docs/introduction), a toolchain which allows creating a native Node module from the rust code. Behind the scenes, the node js implementation will call the Rust code that you can find in crates such as pyaco-validate.

### Running the tool in dev mode

You'll find the detailed explanation on how to run the compiled binary in the [sections](https://github.com/scoville/tailwind-generator#examples) below. In order to run it in dev mode you'll have to replace `pyaco` with `cargo run`. Also, to get more [logs](https://docs.rs/env_logger/0.10.0/env_logger/#example) in dev mode you need to add `RUST_LOG=info`. So in dev mode, the `pyaco validate` command would look like this:

```sh
RUST_LOG=info cargo run validate -c .styles.css -i './src/**/*.tsx' --capture-regex 'Cn\.c\(\s*\n?"([^"]*)",?\n?\s*\)'
```

### Building the rust binary:

- Run `cargo build --release` for compiling the binaries on your architecture

- Build for a specific architecture, e.g. for Mac x86 if you are on an arm64 Mac

```sh
rustup target add x86_64-apple-darwin
cargo build --release --target x86_64-apple-darwin
```

- In order to build the binaries cross-platform you need to have an understanding of how a [makefile](https://www.digitalocean.com/community/tutorials/how-to-use-makefiles-to-automate-repetitive-tasks-on-an-ubuntu-vps) works. Please note there is a Makefile in the main path of this repository. The command to run is `make release`; this will compile the node.js bindings with [Neon](https://neon-bindings.com/docs/hello-world) and build the app cross platform using cargo for Mac and [cross](https://github.com/cross-rs/cross) for Windows and Linux.

### Commands:

To get help:
Expand Down Expand Up @@ -390,6 +413,6 @@ pyaco.validate(
// The callback is required
() => {
console.log("All done");
}
},
);
```
3 changes: 2 additions & 1 deletion npm/getBinary.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ function getPlatform() {
if (type === "Windows_NT" && arch === "x64") return "win64";
if (type === "Linux" && arch === "x64") return "linux";
if (type === "Darwin" && arch === "x64") return "macos";
if (type === "Darwin" && arch === "arm64") return "macos-arm64";

console.warn(
`Unknown platform: ${type} ${arch}.
Defaulting to the node native module which might be slower.
`
`,
);

return null;
Expand Down
Binary file added npm/index.node
Binary file not shown.
6 changes: 3 additions & 3 deletions npm/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ axios({
method: "get",
url: getNativeNodeUrl(),
responseType: "stream",
}).then((response) =>
response.data.pipe(createWriteStream("./npm/index.node"))
);
})
.then((response) => response.data.pipe(createWriteStream("./npm/index.node")))
.then(() => console.log("Installed node native module"));
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pyaco",
"version": "2.0.0-beta-7",
"version": "2.0.0-beta-8",
"repository": "git@github.com:scoville/tailwind-generator.git",
"author": "Kévin COMBRIAT <kevin@sc0ville.com>",
"license": "MIT",
Expand Down
4 changes: 2 additions & 2 deletions pyaco-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ version = "0.1.0"

[dependencies]
anyhow = "1.0.43"
askama = "0.10.5"
askama = "0.12.0"
convert_case = "0.4.0"
cssparser = "0.28.1"
cssparser = "0.29.6"
log = "0.4.14"
ureq = "2.2.0"
url = "2.2.2"
34 changes: 9 additions & 25 deletions pyaco-core/src/classes_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use std::collections::HashSet;

use anyhow::Result;
use cssparser::{
AtRuleParser, AtRuleType, BasicParseError, BasicParseErrorKind, CowRcStr, ParseError, Parser,
ParserState, QualifiedRuleParser, Token,
AtRuleParser, BasicParseError, BasicParseErrorKind, CowRcStr, ParseError, Parser, ParserState,
QualifiedRuleParser, Token,
};

pub struct ClassesParser;
Expand Down Expand Up @@ -62,9 +62,8 @@ impl<'i> QualifiedRuleParser<'i> for ClassesParser {
}

impl<'i> AtRuleParser<'i> for ClassesParser {
type PreludeNoBlock = ();
// `true` if the @rule body should be parsed, `false` otherwise
type PreludeBlock = bool;
type Prelude = bool;
type AtRule = Option<HashSet<String>>;
type Error = ();

Expand All @@ -73,33 +72,18 @@ impl<'i> AtRuleParser<'i> for ClassesParser {
&mut self,
name: CowRcStr<'i>,
input: &mut Parser<'i, 't>,
) -> Result<AtRuleType<Self::PreludeNoBlock, Self::PreludeBlock>, ParseError<'i, Self::Error>>
{
let ret = match name.as_ref() {
// See https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule for more
// "media" is the only @rule we'll parse the body in the `parse_block` function.
"media" => AtRuleType::WithBlock(true),
"supports"
| "page"
| "font-face"
| "keyframes"
| "-webkit-keyframes"
| "counter-style"
| "font-feature-values" => AtRuleType::WithBlock(false),
_ => AtRuleType::WithoutBlock(()),
};

) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
// Consume the rest of the input
while input.next().is_ok() {
continue;
}

Ok(ret)
Ok(name.as_ref() == "media")
}

fn parse_block<'t>(
&mut self,
prelude: Self::PreludeBlock,
prelude: Self::Prelude,
_start: &ParserState,
input: &mut Parser<'i, 't>,
) -> Result<Self::AtRule, ParseError<'i, ()>> {
Expand Down Expand Up @@ -145,9 +129,9 @@ impl<'i> AtRuleParser<'i> for ClassesParser {
// is returned at runtime by the `parse_prelude` function.
fn rule_without_block(
&mut self,
_prelude: Self::PreludeNoBlock,
_prelude: Self::Prelude,
_start: &ParserState,
) -> Self::AtRule {
None
) -> Result<Self::AtRule, ()> {
Ok(None)
}
}
2 changes: 1 addition & 1 deletion pyaco-generate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ version = "0.1.0"
anyhow = "1.0.43"
clap = "3.0.0-beta.4"
log = "0.4.14"
notify = "5.0.0-pre.12"
notify = "5.1.0"
pyaco-core = {path = "../pyaco-core"}
4 changes: 2 additions & 2 deletions pyaco-generate/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use anyhow::Result;
use clap::Clap;
use log::{debug, info, log_enabled, warn, Level};
use notify::event::{DataChange, ModifyKind};
use notify::{Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
use notify::{Event, EventKind, RecursiveMode, Watcher};
use pyaco_core::{
resolve_path, ElmTemplate, InputType, Lang, LangTemplate, PurescriptTemplate, RescriptTemplate,
RescriptTypeTemplate, RescriptiTemplate, TypescriptTemplate, TypescriptType1Template,
Expand Down Expand Up @@ -141,7 +141,7 @@ fn run_watch(
) -> Result<()> {
let (tx, rx) = channel();

let mut watcher = RecommendedWatcher::new(move |result| {
let mut watcher = notify::recommended_watcher(move |result| {
if tx.send(result).is_err() {
debug!("Couldn't send event message to watcher")
}
Expand Down
2 changes: 1 addition & 1 deletion pyaco-node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ tokio = {version = "1.13.1", features = ["full"]}
[dependencies.neon]
default-features = false
features = ["napi-6"]
version = "0.10"
version = "0.10.1"
65 changes: 39 additions & 26 deletions pyaco-node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
extern crate lazy_static;

use neon::prelude::*;
use pyaco_core::Lang;
use pyaco_generate::{run as run_generate, Options as GenerateOptions};
use pyaco_validate::{run as run_validate, Options as ValidateOptions};
use tokio::runtime::Runtime;
Expand All @@ -13,36 +14,38 @@ lazy_static! {
.unwrap();
}

macro_rules! get {
($cx:ident, $options:ident, $name:expr, $type:ty) => {
$options
.get(&mut $cx, $name)?
.downcast_or_throw::<$type, _>(&mut $cx)?
.value(&mut $cx);
};

($cx:ident, $options:ident, $name:expr) => {
get!($cx, $options, $name, JsString);
};
}

fn generate(mut cx: FunctionContext) -> JsResult<JsUndefined> {
let options = cx.argument::<JsObject>(0)?;

let input = get!(cx, options, "input");
let input = options
.get::<JsString, FunctionContext, _>(&mut cx, "input")?
.value(&mut cx);

let lang = get!(cx, options, "lang");
let lang = options.get::<JsString, FunctionContext, _>(&mut cx, "lang");

let lang = match lang.parse() {
let lang = match lang {
Err(_) => return cx.throw_error("Invalid lang"),
Ok(lang) => lang,
Ok(lang) => {
let lang = lang.value(&mut cx);

match lang.parse::<Lang>() {
Ok(lang) => lang,
Err(err) => return cx.throw_error(err),
}
}
};

let output_directory = get!(cx, options, "outputDirectory");
let output_directory = options
.get::<JsString, FunctionContext, _>(&mut cx, "outputDirectory")?
.value(&mut cx);

let output_filename = get!(cx, options, "outputFilename");
let output_filename = options
.get::<JsString, FunctionContext, _>(&mut cx, "outputFilename")?
.value(&mut cx);

let watch = get!(cx, options, "watch", JsBoolean);
let watch = options
.get::<JsBoolean, FunctionContext, _>(&mut cx, "watch")?
.value(&mut cx);

let options = GenerateOptions {
input,
Expand All @@ -63,18 +66,28 @@ fn validate(mut cx: FunctionContext) -> JsResult<JsUndefined> {

let cb = cx.argument::<JsFunction>(1)?;

let capture_regex = get!(cx, options, "captureRegex");
let capture_regex = options
.get::<JsString, FunctionContext, _>(&mut cx, "captureRegex")?
.value(&mut cx);

let css_input = get!(cx, options, "cssInput");
let css_input = options
.get::<JsString, FunctionContext, _>(&mut cx, "cssInput")?
.value(&mut cx);

let input_glob = get!(cx, options, "inputGlob");
let input_glob = options
.get::<JsString, FunctionContext, _>(&mut cx, "inputGlob")?
.value(&mut cx);

// The following will not panic, but the result is not reliable and might
// change depending on the platform (32/64 bits).
// Since we don't expect big numbers to be provided it should work fine though.
let max_opened_files = get!(cx, options, "maxOpenedFiles", JsNumber) as usize;
let max_opened_files = options
.get::<JsNumber, FunctionContext, _>(&mut cx, "maxOpenedFiles")?
.value(&mut cx) as usize;

let split_regex = get!(cx, options, "splitRegex");
let split_regex = options
.get::<JsString, FunctionContext, _>(&mut cx, "splitRegex")?
.value(&mut cx);

let options = ValidateOptions {
capture_regex,
Expand All @@ -93,7 +106,7 @@ fn validate(mut cx: FunctionContext) -> JsResult<JsUndefined> {

let this = cx.undefined();

let args: Vec<Handle<JsUndefined>> = Vec::new();
let args: Vec<Handle<JsValue>> = Vec::new();

cb.call(&mut cx, this, args)?;

Expand Down
2 changes: 1 addition & 1 deletion pyaco/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ clap = "3.0.0-beta.4"
env_logger = "0.9.0"
pyaco-generate = {path = "../pyaco-generate"}
pyaco-validate = {path = "../pyaco-validate"}
tokio = {version = "1.13.1", features = ["full"]}
tokio = {version = "1.27.0", features = ["full"]}

0 comments on commit 5ac3ef8

Please sign in to comment.