diff --git a/Cargo.toml b/Cargo.toml index 2860baf..046074f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ name = "libmake" readme = "README.md" repository = "https://github.com/sebastienrousseau/libmake.git" rust-version = "1.75.0" -version = "0.2.2" +version = "0.2.3" include = [ "/CONTRIBUTING.md", "/LICENSE-APACHE", @@ -54,16 +54,19 @@ debug = true [dependencies] anyhow = "1.0.81" assert_cmd = "2.0.14" -clap = "4.5.3" +clap = "4.5.4" +configparser = "3.0.4" csv = "1.3.0" dtt = "0.0.5" env_logger = "0.11.3" figlet-rs = "0.1.5" -configparser = "3.0.4" -reqwest = { version = "0.12.1", features = ["blocking"] } +log = {version="0.4.21", features = ["std"] } +regex = "1.10.4" +reqwest = { version = "0.12.2", features = ["blocking"] } rlg = "0.0.3" serde = { version = "1.0.197", features = ["derive"] } -serde_json = "1.0.114" +serde_ini = "0.2.0" +serde_json = "1.0.115" serde_yaml = "0.9.33" tempfile = "3.10.1" toml = "0.8.12" diff --git a/README.md b/README.md index fafa7b9..551d576 100644 --- a/README.md +++ b/README.md @@ -356,6 +356,6 @@ providing a lot of useful suggestions on how to improve this project. [crates-badge]: https://img.shields.io/crates/v/libmake.svg?style=for-the-badge "Crates.io Badge" [divider]: https://kura.pro/common/images/elements/divider.svg "divider" [docs-badge]: https://img.shields.io/docsrs/libmake.svg?style=for-the-badge "Docs.rs Badge" -[libs-badge]: https://img.shields.io/badge/lib.rs-v0.2.2-orange.svg?style=for-the-badge "Lib.rs Badge" +[libs-badge]: https://img.shields.io/badge/lib.rs-v0.2.3-orange.svg?style=for-the-badge "Lib.rs Badge" [license-badge]: https://img.shields.io/crates/l/libmake.svg?style=for-the-badge "License Badge" [made-with-rust-badge]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust "Made With Rust Badge" diff --git a/TEMPLATE.md b/TEMPLATE.md index 5616dee..2303608 100644 --- a/TEMPLATE.md +++ b/TEMPLATE.md @@ -5,7 +5,7 @@ alt="LibMake logo" width="261" align="right" /> -# LibMake v0.2.2 ๐Ÿฆ€ +# LibMake v0.2.3 ๐Ÿฆ€ A code generator to reduce repetitive tasks and build high-quality Rust libraries. @@ -64,6 +64,6 @@ The library is designed to be used as a command-line tool. It is available on [C [codecov-badge]: https://img.shields.io/codecov/c/github/sebastienrousseau/libmake?style=for-the-badge&token=Q9KJ6XXL67 "Codecov Badge" [crates-badge]: https://img.shields.io/crates/v/libmake.svg?style=for-the-badge "Crates.io Badge" [docs-badge]: https://img.shields.io/docsrs/libmake.svg?style=for-the-badge "Docs.rs Badge" -[libs-badge]: https://img.shields.io/badge/lib.rs-v0.2.2-orange.svg?style=for-the-badge "Lib.rs Badge" +[libs-badge]: https://img.shields.io/badge/lib.rs-v0.2.3-orange.svg?style=for-the-badge "Lib.rs Badge" [license-badge]: https://img.shields.io/crates/l/libmake.svg?style=for-the-badge "License Badge" [made-with-rust-badge]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust "Made With Rust Badge" diff --git a/examples/generate_from_args.rs b/examples/generate_from_args.rs index 89b491b..f42c328 100644 --- a/examples/generate_from_args.rs +++ b/examples/generate_from_args.rs @@ -28,7 +28,7 @@ //! If there is an error, it will print an error message. // Import the necessary function for generating files from arguments -use libmake::generator::generate_from_args; +use libmake::generators::args::generate_from_args; /// A simple test program for the `generate_from_args` function. /// diff --git a/examples/generate_from_csv.rs b/examples/generate_from_csv.rs index 3a7bcf8..a58037f 100644 --- a/examples/generate_from_csv.rs +++ b/examples/generate_from_csv.rs @@ -31,7 +31,7 @@ //! ``` // Import the necessary function for generating templates from a CSV file. -use libmake::generator::generate_from_csv; +use libmake::generators::csv::generate_from_csv; /// Attempts to generate template files from the specified CSV file. /// @@ -48,7 +48,7 @@ use libmake::generator::generate_from_csv; /// The following example demonstrates how to use the `generate_from_csv` function: /// /// ```rust -/// use libmake::generator::generate_from_csv; +/// use libmake::generators::csv::generate_from_csv; /// /// let csv_file_path = "./tests/data/mylibrary.csv"; /// diff --git a/examples/generate_from_json.rs b/examples/generate_from_json.rs index b626724..676dffc 100644 --- a/examples/generate_from_json.rs +++ b/examples/generate_from_json.rs @@ -34,7 +34,7 @@ //! ``` // Import the necessary function for generating templates from a JSON file. -use libmake::generator::generate_from_json; +use libmake::generators::json::generate_from_json; /// Generate template files based on the data in the JSON file. /// diff --git a/examples/generate_from_toml.rs b/examples/generate_from_toml.rs index 4daa182..424b070 100644 --- a/examples/generate_from_toml.rs +++ b/examples/generate_from_toml.rs @@ -29,7 +29,7 @@ //! ``` //! // Import the necessary function for generating templates from a TOML file. -use libmake::generator::generate_from_toml; +use libmake::generators::toml::generate_from_toml; /// Generate template files based on the configuration in the TOML file. /// diff --git a/examples/generate_from_yaml.rs b/examples/generate_from_yaml.rs index ec77f7c..c37b205 100644 --- a/examples/generate_from_yaml.rs +++ b/examples/generate_from_yaml.rs @@ -30,7 +30,7 @@ //! ``` // Import the necessary function for generating templates from a YAML file. -use libmake::generator::generate_from_yaml; +use libmake::generators::yaml::generate_from_yaml; /// Generate template files from the specified YAML file. /// diff --git a/output_dir/.deepsource.toml b/output_dir/.deepsource.toml deleted file mode 100644 index d052a12..0000000 --- a/output_dir/.deepsource.toml +++ /dev/null @@ -1,8 +0,0 @@ -version = 1 - -[[analyzers]] -name = "rust" -enabled = true - - [analyzers.meta] - msrv = "stable" diff --git a/output_dir/.github/workflows/ci.yml b/output_dir/.github/workflows/ci.yml deleted file mode 100644 index 8930143..0000000 --- a/output_dir/.github/workflows/ci.yml +++ /dev/null @@ -1,486 +0,0 @@ -name: โฏ test_lib release - -on: - pull_request: - branches: - - main - - 'feat/*' - push: - branches: - - main - - 'feat/*' - -jobs: - # This job checks a local package and all of its dependencies for - # errors. - check: - name: โฏ Check ๐Ÿ’ต - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - rust: stable - target: x86_64-unknown-linux-gnu - os: ubuntu-latest - - steps: - # Check out the repository code - - name: Checkout sources - id: checkout - uses: actions/checkout@v4 - - # Install the stable Rust toolchain - - name: Install stable toolchain - id: install-toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - - # Cache dependencies to speed up subsequent builds - - name: Cache dependencies - id: cache-dependencies - uses: actions/cache@v3 - with: - path: ~/.cargo - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo- - - # Run cargo check to check for errors - - uses: actions-rs/cargo@v1 - with: - command: check - args: --all-targets --workspace --all-features - - # This job runs the tests for the project. - test: - name: โฏ Test ๐Ÿงช - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - rust: stable - target: x86_64-unknown-linux-gnu - - steps: - # Check out the repository code - - name: Checkout sources - id: checkout - uses: actions/checkout@v4 - - # Install the stable Rust toolchain - - name: Install stable toolchain - id: install-toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ matrix.rust }} - - # Cache dependencies to speed up subsequent builds - - name: Cache dependencies - id: cache-dependencies - uses: actions/cache@v3 - with: - path: ~/.cargo - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo- - - # Run cargo hack to check for errors - - name: Install cargo-hack - uses: taiki-e/install-action@cargo-hack - id: install-cargo-hack - - - run: cargo test --all-targets --workspace --all-features - - # This job runs the tests for the project. - coverage: - name: โฏ Coverage ๐Ÿ“Š - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - runs-on: ubuntu-latest - strategy: - matrix: - include: - - rust: stable - target: x86_64-unknown-linux-gnu - - steps: - # Check out the repository code - - name: Checkout sources - id: checkout - uses: actions/checkout@v4 - - # Install the stable Rust toolchain - - name: Install stable toolchain - id: install-toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ matrix.rust }} - override: true - components: llvm-tools-preview - - # Cache dependencies to speed up subsequent builds - - name: Cache dependencies - id: cache-dependencies - uses: actions/cache@v3 - with: - path: ~/.cargo - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo- - - # Install grcov - - name: Install grcov - run: | - mkdir -p "${HOME}/.local/bin" - curl -sL https://github.com/mozilla/grcov/releases/download/v0.8.18/grcov-x86_64-unknown-linux-gnu.tar.bz2 | tar jxf - -C "${HOME}/.local/bin" - echo "$HOME/.local/bin" >> $GITHUB_PATH - - # Use grcov to generate a coverage report - - name: Generate coverage report - id: coverage - uses: actions-rs/cargo@v1 - with: - command: xtask - args: coverage - - # Upload the coverage report to codecov - - name: Upload coverage report to codecov - id: codecov - uses: codecov/codecov-action@v3 - with: - files: coverage/*.lcov - - lints: - name: โฏ Lints ๐Ÿงน - runs-on: ubuntu-latest - strategy: - matrix: - include: - - rust: stable - target: x86_64-unknown-linux-gnu - steps: - # Check out the repository code - - name: Checkout sources - id: checkout - uses: actions/checkout@v4 - with: - submodules: true - - # Install the stable Rust toolchain - - name: Install stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - components: clippy - - # Cache dependencies to speed up subsequent builds - - name: Cache dependencies - uses: actions/cache@v3 - with: - path: ~/.cargo - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo- - - # Run cargo clippy to check for linting errors - - name: Run cargo clippy - if: github.ref == !github.event.check_run.conclusion - uses: actions-rs/cargo@v1 - with: - command: clippy - args: --all-targets --all-features -- -D warnings - - # Run Cargo Format for the code style - - name: Run Cargo Format - id: run-check-format - if: github.ref == !github.event.check_run.conclusion - run: | - cargo check --all --all-features --workspace --verbose - - # Run cargo clippy to check for linting errors - - name: Run Clippy - id: run-check-clippy - if: github.ref == !github.event.check_run.conclusion - run: | - cargo clippy --all-targets --all-features --workspace -- -D warnings - - - build: - # This job builds the project for all the targets and generates a - # release artifact that contains the binaries for all the targets. - name: โฏ Build ๐Ÿ›  - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - strategy: - fail-fast: false - matrix: - target: - # List of targets: https://doc.rust-lang.org/nightly/rustc/platform-support.html - - # FreeBSD targets ๐Ÿฌ - - x86_64-unknown-freebsd # 64-bit FreeBSD on x86-64 โœ… Tested - - # Linux targets ๐Ÿง - - aarch64-unknown-linux-gnu # 64-bit Linux systems on ARM architecture โœ… Tested - - aarch64-unknown-linux-musl # 64-bit Linux systems on ARM architecture โœ… Tested - - arm-unknown-linux-gnueabi # ARMv6 Linux (kernel 3.2, glibc 2.17) โœ… Tested - - armv7-unknown-linux-gnueabihf # ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17) โœ… Tested - - i686-unknown-linux-gnu # 32-bit Linux (kernel 3.2+, glibc 2.17+) โœ… Tested - - i686-unknown-linux-musl # 32-bit Linux (kernel 3.2+, musl libc) โœ… Tested - - x86_64-unknown-linux-gnu # 64-bit Linux (kernel 2.6.32+, glibc 2.11+) โœ… Tested - - x86_64-unknown-linux-musl # 64-bit Linux (kernel 2.6.32+, musl libc) โœ… Tested - - # macOS targets ๐ŸŽ - - aarch64-apple-darwin # 64-bit macOS on Apple Silicon โœ… Tested - - x86_64-apple-darwin # 64-bit macOS (10.7 Lion or later) โœ… Tested - - # Illumos targets ๐ŸŒž - - x86_64-unknown-illumos # 64-bit Illumos on x86-64 โœ… Tested - - include: - # FreeBSD targets ๐Ÿฌ - - target: x86_64-unknown-freebsd - os: ubuntu-latest - cross: true - - # Linux targets ๐Ÿง - - target: aarch64-unknown-linux-gnu - os: ubuntu-latest - cross: true - - target: aarch64-unknown-linux-musl - os: ubuntu-latest - cross: true - - target: arm-unknown-linux-gnueabi - os: ubuntu-latest - cross: true - - target: armv7-unknown-linux-gnueabihf - os: ubuntu-latest - cross: true - - target: i686-unknown-linux-gnu - os: ubuntu-latest - cross: true - - target: i686-unknown-linux-musl - os: ubuntu-latest - cross: true - - target: x86_64-unknown-linux-gnu - os: ubuntu-latest - cross: true - - target: x86_64-unknown-linux-musl - os: ubuntu-latest - cross: true - - # Illumos targets ๐ŸŒž - - target: x86_64-unknown-illumos - os: ubuntu-latest - cross: true - - # macOS targets ๐ŸŽ - - target: aarch64-apple-darwin - os: macos-latest - cross: true - - target: x86_64-apple-darwin - os: macos-latest - cross: true - - runs-on: ${{ matrix.os }} - - steps: - # Check out the repository code - - name: Checkout sources - id: checkout - uses: actions/checkout@v4 - - # Install the stable Rust toolchain - - name: Install stable toolchain - id: install-toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - - # Cache dependencies to speed up subsequent builds - - name: Cache dependencies - id: cache-dependencies - uses: actions/cache@v3 - with: - path: ~/.cargo - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo- - - # Install the targets for the cross compilation toolchain - - name: Install target - id: install-target - run: rustup target add ${{ matrix.target }} - - # Update the version number based on the Cargo.toml file - - name: Update version number - id: update-version - run: | - NEW_VERSION=$(grep version Cargo.toml | sed -n 2p | cut -d '"' -f 2) - echo "VERSION=$NEW_VERSION" >> $GITHUB_ENV - shell: /bin/bash -e {0} - - # Install the cross compilation toolchain - - name: Install Cross - id: install-cross - run: | - # Install cross - cargo install cross - # Clean the build artifacts - cargo clean --verbose - shell: /bin/bash -e {0} - - # Build the targets - - name: Build targets - id: build-targets - uses: actions-rs/cargo@v1 - with: - use-cross: true - command: build - args: --verbose --workspace --release --target ${{ matrix.target }} - - # Package the binary for each target - - name: Package the binary - id: package-binary - run: | - mkdir -p target/package - tar czf target/package/${{ matrix.target }}.tar.gz -C target/${{ matrix.target }}/release . - echo "${{ matrix.target }}.tar.gz=target/package/${{ matrix.target }}.tar.gz" >> $GITHUB_ENV - - # Upload the binary for each target - - name: Upload the binary - id: upload-binary - uses: actions/upload-artifact@v2 - with: - name: ${{ matrix.target }}.tar.gz - path: ${{ env[format('{0}.tar.gz', matrix.target)] }} - - # Release the binary to GitHub Releases - release: - name: โฏ Release ๐Ÿš€ - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - needs: build - runs-on: ubuntu-latest - steps: - # Check out the repository code - - name: Checkout sources - uses: actions/checkout@v4 - - # Install the stable Rust toolchain - - name: Install stable toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - - # Update the version number based on the Cargo.toml file - - name: Update version number - run: | - NEW_VERSION=$(grep version Cargo.toml | sed -n 2p | cut -d '"' -f 2) - echo "VERSION=$NEW_VERSION" >> $GITHUB_ENV - shell: /bin/bash -e {0} - - # Cache dependencies to speed up subsequent builds - - name: Cache dependencies - uses: actions/cache@v3 - with: - path: ~/.cargo - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo- - - # Download the artifacts from the build job - - name: Download artifacts - run: | - for target in x86_64-unknown-freebsd aarch64-unknown-linux-gnu aarch64-unknown-linux-musl arm-unknown-linux-gnueabi armv7-unknown-linux-gnueabihf i686-unknown-linux-gnu i686-unknown-linux-musl x86_64-unknown-linux-gnu x86_64-unknown-linux-musl aarch64-apple-darwin x86_64-apple-darwin x86_64-unknown-illumos; do - echo "Downloading $target artifact" - name="${target}.tar.gz" - echo "Artifact name: $name" - mkdir -p target/package - curl -sSL -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/vnd.github.v3+json" -L "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}/artifacts/$test_lib" -o "target/package/$test_lib" - done - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - RUN_ID: ${{ github.event.workflow_run.id }} - - # Generate the changelog based on git log and template file - - name: Generate Changelog - run: | - # Append version information to CHANGELOG.md - echo "## Release v${{ env.VERSION }} - $(date +'%Y-%m-%d')" >> ${{ github.workspace }}/CHANGELOG.md - # Copy content of template file to CHANGELOG.md - cat TEMPLATE.md >> ${{ github.workspace }}/CHANGELOG.md - # Append git log to CHANGELOG.md - echo "$(git log --pretty=format:'%s' --reverse $(git describe --tags --abbrev=0)..HEAD)" >> ${{ github.workspace }}/CHANGELOG.md - # Append empty line to CHANGELOG.md - echo "" >> ${{ github.workspace }}/CHANGELOG.md - - # Append the artifact links to the changelog - - name: Append Artifact Links - run: | - echo "" >> ${{ github.workspace }}/CHANGELOG.md - echo "## Artifacts ๐ŸŽ" >> ${{ github.workspace }}/CHANGELOG.md - for filename in target/package/*.tar.gz; do - link="$(basename $filename)" - echo "* [$link](${{ github.server_url }}/${{ github.repository }}/releases/download/v${{ env.VERSION }}/$link)" >> ${{ github.workspace }}/CHANGELOG.md - done - - # Create the release on GitHub Releases - - name: Create Release - id: create-release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: v${{ env.VERSION }} - release_name: test_lib ๐Ÿฆ€ v${{ env.VERSION }} - body_path: ${{ github.workspace }}/CHANGELOG.md - draft: true - prerelease: false - - # Publish the release to Crates.io automatically - crate: - name: โฏ Crate.io ๐Ÿฆ€ - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - needs: release - runs-on: ubuntu-latest - - steps: - # Check out the repository code - - name: Checkout - uses: actions/checkout@v4 - - # Install the stable Rust toolchain - - name: Install stable toolchain - id: install-toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - - # Cache dependencies to speed up subsequent builds - - name: Cache dependencies - id: cache-dependencies - uses: actions/cache@v2 - with: - path: /home/runner/.cargo/registry/index/ - key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo-index- - - # Update the version number based on the Cargo.toml file - - name: Update version number - id: update-version - run: | - NEW_VERSION=$(grep version Cargo.toml | sed -n 2p | cut -d '"' -f 2) - echo "VERSION=$NEW_VERSION" >> $GITHUB_ENV - shell: /bin/bash -e {0} - - # Publish the Rust library to Crate.io - - name: Publish Library to Crate.io - id: publish-library - uses: actions-rs/cargo@v1 - env: - CARGO_API_TOKEN: ${{ secrets.CARGO_API_TOKEN }} - with: - use-cross: true - command: publish - args: --dry-run --verbose --token "${CARGO_API_TOKEN}" diff --git a/output_dir/.gitignore b/output_dir/.gitignore deleted file mode 100644 index 7b5a0e0..0000000 --- a/output_dir/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -*.DS_Store -*.profraw -/.vscode/ -/output/ -/public/ -/target/ -build -Icon? -src/.DS_Store -tarpaulin-report.html diff --git a/output_dir/AUTHORS.md b/output_dir/AUTHORS.md deleted file mode 100644 index ff5d1ca..0000000 --- a/output_dir/AUTHORS.md +++ /dev/null @@ -1,3 +0,0 @@ -# Authors - -* [John Doe](john@example.com) (Original Contributor) diff --git a/output_dir/CONTRIBUTING.md b/output_dir/CONTRIBUTING.md deleted file mode 100644 index 663298a..0000000 --- a/output_dir/CONTRIBUTING.md +++ /dev/null @@ -1,81 +0,0 @@ -# Contributing to `test_lib` - -Welcome! We're thrilled that you're interested in contributing to the -`test_lib` library. Whether you're looking to evangelize, submit feedback, -or contribute code, we appreciate your involvement in making `test_lib` a -better tool for everyone. Here's how you can get started. - -## Evangelize - -One of the simplest ways to help us out is by spreading the word about -test_lib. We believe that a bigger, more involved community makes for a -better framework, and that better frameworks make the world a better -place. If you know people who might benefit from using test_lib, please -let them know! - -## How to Contribute - -If you're interested in making a more direct contribution, there are -several ways you can help us improve test_lib. Here are some guidelines -for submitting feedback, bug reports, and code contributions. - -### Feedback - -Your feedback is incredibly valuable to us, and we're always looking for -ways to make test_lib better. If you have ideas, suggestions, or questions -about test_lib, we'd love to hear them. Here's how you can provide -feedback: - -- Click [here][2] to submit a new feedback. -- Use a descriptive title that clearly summarizes your feedback. -- Provide a detailed description of the issue or suggestion. -- Be patient while we review and respond to your feedback. - -### Bug Reports - -If you encounter a bug while using test_lib, please let us know so we can -fix it. Here's how you can submit a bug report: - -- Click [here][2] to submit a new issue. -- Use a descriptive title that clearly summarizes the bug. -- Provide a detailed description of the issue, including steps to - reproduce it. -- Be patient while we review and respond to your bug report. - -### Code Contributions - -If you're interested in contributing code to test_lib, we're excited to -have your help! Here's what you need to know: - -#### Feature Requests - -If you have an idea for a new feature or improvement, we'd love to hear -it. Here's how you can contribute code for a new feature to test_lib: - -- Fork the repo. -- Clone the test_lib[1] repo by running: - `git clone https://github.com/test/test_lib` -- Edit files in the `src/` folder. The `src/` folder contains the source - code for test_lib. -- Submit a pull request, and we'll review and merge your changes if they - fit with our vision for test_lib. - -#### Submitting Code - -If you've identified a bug or have a specific code improvement in mind, -we welcome your pull requests. Here's how to submit your code changes: - -- Fork the repo. -- Clone the test_lib repo by running: - `git clone https://github.com/test/test_lib` -- Edit files in the `src/` folder. The `src/` folder contains the source - code for test_lib. -- Submit a pull request, and we'll review and merge your changes if they - fit with our vision for test_lib. - -We hope that this guide has been helpful in explaining how you can -contribute to test_lib. Thank you for your interest and involvement in our -project! - -[1]: https://github.com/test/test_lib -[2]: https://github.com/test/test_lib/issues/newHTTP/2 416 diff --git a/output_dir/Cargo.toml b/output_dir/Cargo.toml deleted file mode 100644 index 41e46ad..0000000 --- a/output_dir/Cargo.toml +++ /dev/null @@ -1,137 +0,0 @@ -[package] -authors = ["John Doe "] -build = "script.rs" -categories = [category1,category2] -description = "A test library" -documentation = "https://docs.rs/test_lib" -edition = "2021" -exclude = [ - "/.git/*", - "/.github/*", - "/.gitignore", - "/.vscode/*" - ] -homepage = "https://example.com" -keywords = ["keyword1,keyword2"] -license = "MIT" -name = "test_lib" -readme = "{readme}" -repository = "https://github.com/test/test_lib" -rust-version = "1.60.0" -version = "0.1.0" -include = [ - "/benches/**", - "/build.rs", - "/Cargo.toml", - "/CONTRIBUTING.md", - "/examples/**", - "/LICENSE-APACHE", - "/LICENSE-MIT", - "/README.md", - "/src/**", - "/tests/**" -] - -[[bench]] -name = "benchmark" -harness = false -path = "benches/criterion.rs" - -[profile.bench] -debug = true - -[dependencies] -anyhow = "1.0.81" -dtt = "0.0.5" -env_logger = "0.11.3" -rlg = "0.0.3" -serde = { version = "1.0.197", features = ["derive"] } -serde_json = "1.0.114" -serde_yaml = "0.9.33" -toml = "0.8.12" -vrd = "0.0.6" - -[dev-dependencies] -criterion = "0.5.1" - -[lib] -crate-type = ["lib"] -name = "test_lib" -path = "src/lib.rs" - -[features] -default = [] - -[package.metadata.docs.rs] -all-features = true - -# Linting config -[lints.rust] - -## Forbid -missing_debug_implementations = "forbid" -missing_docs = "warn" -non_ascii_idents = "forbid" -unreachable_pub = "forbid" -unsafe_code = "forbid" - -## Deny -dead_code = "deny" -deprecated_in_future = "deny" -ellipsis_inclusive_range_patterns = "deny" -explicit_outlives_requirements = "deny" -future_incompatible = "deny" -keyword_idents = "deny" -macro_use_extern_crate = "deny" -meta_variable_misuse = "deny" -missing_fragment_specifier = "deny" -noop_method_call = "deny" -pointer_structural_match = "deny" -rust_2018_idioms = "deny" -rust_2021_compatibility = "deny" -single_use_lifetimes = "deny" -trivial_casts = "deny" -trivial_numeric_casts = "deny" -unused = "deny" -unused_features = "deny" -unused_import_braces = "deny" -unused_labels = "deny" -unused_lifetimes = "deny" -unused_macro_rules = "deny" -unused_qualifications = "deny" -variant_size_differences = "deny" - -[profile.dev] -codegen-units = 256 -debug = true -debug-assertions = true -incremental = true -lto = false -opt-level = 0 -overflow-checks = true -panic = 'unwind' -rpath = false -strip = false - -[profile.release] -codegen-units = 1 -debug = false -debug-assertions = false -incremental = false -lto = true -opt-level = "s" -overflow-checks = false -panic = "abort" -rpath = false -strip = "symbols" - -[profile.test] -codegen-units = 256 -debug = true -debug-assertions = true -incremental = true -lto = false -opt-level = 0 -overflow-checks = true -rpath = false -strip = false diff --git a/output_dir/README.md b/output_dir/README.md deleted file mode 100644 index bc5942d..0000000 --- a/output_dir/README.md +++ /dev/null @@ -1,197 +0,0 @@ - - - - - - -# test_lib - -A test library - - -
- - -[![Made With Rust][made-with-rust-badge]][5] -[![Crates.io][crates-badge]][7] -[![Lib.rs][libs-badge]][9] -[![Docs.rs][docs-badge]][8] -[![License][license-badge]][2] - -โ€ข [Website][0] -โ€ข [Documentation][8] -โ€ข [Report Bug][3] -โ€ข [Request Feature][3] -โ€ข [Contributing Guidelines][4] - - -
- - -![divider][divider] - -## Overview ๐Ÿ“– - -A test library - -## Features โœจ - -- Feature 1 -- Feature 2 -- Feature 3 - -## Getting Started ๐Ÿš€ - -It takes just a few minutes to get up and running with `test_lib`. - -### Installation - -To install `test_lib`, you need to have the Rust toolchain installed on -your machine. You can install the Rust toolchain by following the -instructions on the [Rust website][13]. - -Once you have the Rust toolchain installed, you can install `test_lib` -using the following command: - -```shell -cargo install test_lib -``` - -You can then run the help command to see the available options: - -```shell -test_lib --help -``` - -### Requirements - -The minimum supported Rust toolchain version is currently Rust -**1.60.0** or later (stable). - -### Platform support - -`test_lib` is supported and tested on the following platforms: - -### Tier 1 platforms ๐Ÿ† - -| | Operating System | Target | Description | -| --- | --- | --- | --- | -| โœ… | Linux | aarch64-unknown-linux-gnu | 64-bit Linux systems on ARM architecture | -| โœ… | Linux | i686-unknown-linux-gnu | 32-bit Linux (kernel 3.2+, glibc 2.17+) | -| โœ… | Linux | x86_64-unknown-linux-gnu | 64-bit Linux (kernel 2.6.32+, glibc 2.11+) | -| โœ… | macOS | x86_64-apple-darwin | 64-bit macOS (10.7 Lion or later) | -| โœ… | Windows | i686-pc-windows-gnu | 32-bit Windows (7 or later) | -| โœ… | Windows | i686-pc-windows-msvc | 32-bit Windows (7 or later) | -| โœ… | Windows | x86_64-pc-windows-gnu | 64-bit Windows (7 or later) | -| โœ… | Windows | x86_64-pc-windows-msvc | 64-bit Windows (7 or later) | - -### Tier 2 platforms ๐Ÿฅˆ - -| | Operating System | Target | Description | -| --- | --- | --- | --- | -| โœ… | Linux | aarch64-unknown-linux-musl | 64-bit Linux systems on ARM architecture | -| โœ… | Linux | arm-unknown-linux-gnueabi | ARMv6 Linux (kernel 3.2, glibc 2.17) | -| โœ… | Linux | arm-unknown-linux-gnueabihf | ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17) | -| โœ… | Linux | armv7-unknown-linux-gnueabihf | ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17) | -| โœ… | Linux | mips-unknown-linux-gnu | MIPS Linux (kernel 2.6.32+, glibc 2.11+) | -| โœ… | Linux | mips64-unknown-linux-gnuabi64 | MIPS64 Linux (kernel 2.6.32+, glibc 2.11+) | -| โœ… | Linux | mips64el-unknown-linux-gnuabi64 | MIPS64 Linux (kernel 2.6.32+, glibc 2.11+) | -| โœ… | Linux | mipsel-unknown-linux-gnu | MIPS Linux (kernel 2.6.32+, glibc 2.11+) | -| โœ… | macOS | aarch64-apple-darwin | 64-bit macOS (10.7 Lion or later) | -| โœ… | Windows | aarch64-pc-windows-msvc | 64-bit Windows (7 or later) | - -The [GitHub Actions][10] shows the platforms in which the `test_lib` -library tests are run. - -### Documentation - -**Info:** Please check out our [website][0] for more information. You can find our documentation on [docs.rs][8], [lib.rs][9] and -[crates.io][7]. - -## Usage ๐Ÿ“– - -To use the `test_lib` library in your project, add the following to your -`Cargo.toml` file: - -```toml -[dependencies] -test_lib = "0.1.0" -``` - -Add the following to your `main.rs` file: - -```rust -extern crate test_lib; -use test_lib::*; -``` - -then you can use the functions in your application code. - -### Examples - -To get started with `test_lib`, you can use the examples provided in the -`examples` directory of the project. - -To run the examples, clone the repository and run the following command -in your terminal from the project root directory. - -```shell -cargo run --example test_lib -``` - -## Semantic Versioning Policy ๐Ÿšฅ - -For transparency into our release cycle and in striving to maintain -backward compatibility, `test_lib` follows [semantic versioning][6]. - -## License ๐Ÿ“ - -The project is licensed under the terms of MIT. - -## Contribution ๐Ÿค - -We welcome all people who want to contribute. Please see the -[contributing instructions][4] for more information. - -Contributions in any form (issues, pull requests, etc.) to this project -must adhere to the [Rust's Code of Conduct][11]. - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the -Apache-2.0 license, shall be dual licensed as above, without any -additional terms or conditions. - -## Acknowledgements ๐Ÿ’™ - -A big thank you to all the awesome contributors of [test_lib][5] for their -help and support. - -A special thank you goes to the [Rust Reddit][12] community for -providing a lot of useful suggestions on how to improve this project. - -[0]: https://example.com -[2]: http://opensource.org/licenses/MIT -[3]: https://github.com/test/test_lib/test_lib/issues -[4]: https://github.com/test/test_lib/test_lib/blob/main/CONTRIBUTING.md -[5]: https://github.com/test/test_lib/test_lib/graphs/contributors -[6]: http://semver.org/ -[7]: https://crates.io/crates/test_lib -[8]: https://docs.rs/test_lib -[9]: https://lib.rs/crates/test_lib -[10]: https://github.com/test/test_lib/test_lib/actions -[11]: https://www.rust-lang.org/policies/code-of-conduct -[12]: https://www.reddit.com/r/rust/ -[13]: https://www.rust-lang.org/learn/get-started - -[crates-badge]: https://img.shields.io/crates/v/test_lib.svg?style=for-the-badge 'Crates.io badge' -[divider]: https://kura.pro/common/images/elements/divider.svg "divider" -[docs-badge]: https://img.shields.io/docsrs/test_lib.svg?style=for-the-badge 'Docs.rs badge' -[libs-badge]: https://img.shields.io/badge/lib.rs-v0.1.0-orange.svg?style=for-the-badge 'Lib.rs badge' -[license-badge]: https://img.shields.io/crates/l/test_lib.svg?style=for-the-badge 'License badge' -[made-with-rust-badge]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust badge' diff --git a/output_dir/TEMPLATE.md b/output_dir/TEMPLATE.md deleted file mode 100644 index 809c9a7..0000000 --- a/output_dir/TEMPLATE.md +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - -# test_lib - -A test library - - -
- - -[![Made With Rust][made-with-rust-badge]][5] -[![Crates.io][crates-badge]][7] -[![Lib.rs][libs-badge]][9] -[![Docs.rs][docs-badge]][8] -[![License][license-badge]][2] - -โ€ข [Website][0] -โ€ข [Documentation][8] -โ€ข [Report Bug][3] -โ€ข [Request Feature][3] -โ€ข [Contributing Guidelines][4] - - -
- - -![divider][divider] - -## Overview ๐Ÿ“– - -A test library - -## Features โœจ - -- Feature 1 -- Feature 2 -- Feature 3 - -## Changelog ๐Ÿ“š - -- - -[0]: https://example.com -[2]: http://opensource.org/licenses/MIT -[3]: https://github.com/test/test_lib/test_lib/issues -[4]: https://github.com/test/test_lib/test_lib/blob/main/CONTRIBUTING.md -[5]: https://github.com/test/test_lib/test_lib/graphs/contributors -[7]: https://crates.io/crates/test_lib -[8]: https://docs.rs/test_lib -[9]: https://lib.rs/crates/test_lib - -[banner]: https://via.placeholder.com/1500x500.png/000000/FFFFFF?text=test_lib "test_lib's banner" -[crates-badge]: https://img.shields.io/crates/v/test_lib.svg?style=for-the-badge 'Crates.io badge' -[divider]: https://via.placeholder.com/1024x1.png/d8dee4/FFFFFF?text=โˆ’ "test_lib's divider" -[docs-badge]: https://img.shields.io/docsrs/test_lib.svg?style=for-the-badge 'Docs.rs badge' -[libs-badge]: https://img.shields.io/badge/lib.rs-v0.1.0-orange.svg?style=for-the-badge 'Lib.rs badge' -[license-badge]: https://img.shields.io/crates/l/test_lib.svg?style=for-the-badge 'License badge' -[made-with-rust-badge]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust badge' diff --git a/output_dir/benches/criterion.rs b/output_dir/benches/criterion.rs deleted file mode 100644 index fcf3672..0000000 --- a/output_dir/benches/criterion.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright notice and licensing information. -// These lines indicate the copyright of the software and its licensing terms. -// Copyright ยฉ 2024 test_lib. All rights reserved. -// SPDX-License-Identifier: MIT - -extern crate criterion; - -use criterion::{criterion_group, criterion_main, Criterion}; -use test_lib::{run, test_lib_vec, test_lib_map, test_lib_join}; - -fn test_lib_vec_benchmark(c: &mut Criterion) { - c.bench_function("test_lib_vec_macro", |b| { - b.iter(|| { - test_lib_vec![1, 2, 3, 4, 5] - }) - }); -} - -fn test_lib_map_benchmark(c: &mut Criterion) { - c.bench_function("test_lib_map_macro", |b| { - b.iter(|| { - test_lib_map!["a" => 1, "b" => 2, "c" => 3, "d" => 4, "e" => 5] - }) - }); -} - -fn test_lib_join_benchmark(c: &mut Criterion) { - c.bench_function("test_lib_join_macro", |b| { - b.iter(|| { - test_lib_join!["a", "b", "c", "d", "e"] - }) - }); -} - -fn test_lib_benchmark(c: &mut Criterion) { - c.bench_function("test_lib", |b| { - b.iter(|| { - for _ in 0..1000 { - run().unwrap(); - } - }) - }); -} - -criterion_group!( - test_lib_macros_benchmark, - test_lib_vec_benchmark, - test_lib_map_benchmark, - test_lib_join_benchmark, - test_lib_benchmark -); -criterion_main!(test_lib_macros_benchmark); diff --git a/output_dir/build.rs b/output_dir/build.rs deleted file mode 100644 index 8ca0c3e..0000000 --- a/output_dir/build.rs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright notice and licensing information. -// These lines indicate the copyright of the software and its licensing terms. -// Copyright ยฉ 2024 test_lib. All rights reserved. -// SPDX-License-Identifier: MIT - -//! This is the main function for the build script. -//! -//! Currently, it only instructs Cargo to re-run this build script if `build.rs` is changed. -fn main() { - // Avoid unnecessary re-building. - println!("cargo:rerun-if-changed=build.rs"); -} diff --git a/output_dir/deny.toml b/output_dir/deny.toml deleted file mode 100644 index 2670118..0000000 --- a/output_dir/deny.toml +++ /dev/null @@ -1,71 +0,0 @@ -[licenses] -# The lint level for crates which do not have a detectable license -unlicensed = "deny" - -# List of explicitly allowed licenses -# See https://spdx.org/licenses/ for list of possible licenses -# [possible values: any SPDX 3.7 short identifier (+ optional exception)]. -allow = [ - "Apache-2.0", - "MIT", - "CC0-1.0", - "ISC", - "0BSD", - "BSD-2-Clause", - "BSD-3-Clause", - "Unlicense", - "Unicode-DFS-2016", -] - -# List of banned licenses -[bans] -multiple-versions = "deny" - - -# The lint level for licenses considered copyleft -copyleft = "deny" - -# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses -# * both - The license will only be approved if it is both OSI-approved *AND* FSF/Free -# * either - The license will be approved if it is either OSI-approved *OR* FSF/Free -# * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF/Free -# * fsf-only - The license will be approved if is FSF/Free *AND NOT* OSI-approved -# * neither - The license will be denied if is FSF/Free *OR* OSI-approved -allow-osi-fsf-free = "either" - -# The confidence threshold for detecting a license from license text. -# The higher the value, the more closely the license text must be to the -# canonical license text of a valid SPDX license file. -# [possible values: any between 0.0 and 1.0]. -confidence-threshold = 0.8 - -# The graph highlighting used when creating dotgraphs for crates -# with multiple versions -# * lowest-version - The path to the lowest versioned duplicate is highlighted -# * simplest-path - The path to the version with the fewest edges is highlighted -# * all - Both lowest-version and simplest-path are used -highlight = "all" - -# List of crates that are allowed. Use with care! -allow = [] - -# List of crates to deny -deny = [ - # Each entry the name of a crate and a version range. If version is - # not specified, all versions will be matched. -] - -# Certain crates/versions that will be skipped when doing duplicate detection. -skip = [] - -# Similarly to `skip` allows you to skip certain crates during duplicate detection, -# unlike skip, it also includes the entire tree of transitive dependencies starting at -# the specified crate, up to a certain depth, which is by default infinite -skip-tree = [] - - -[advisories] -notice = "deny" -unmaintained = "deny" -unsound = "deny" -vulnerability = "deny" diff --git a/output_dir/examples/example.rs b/output_dir/examples/example.rs deleted file mode 100644 index 2a778e4..0000000 --- a/output_dir/examples/example.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - -} diff --git a/output_dir/rustfmt.toml b/output_dir/rustfmt.toml deleted file mode 100644 index a38e84e..0000000 --- a/output_dir/rustfmt.toml +++ /dev/null @@ -1,32 +0,0 @@ -# SPDX-FileCopyrightText: Copyright ยฉ 2023 test_lib. All rights reserved. -# SPDX-License-Identifier: MIT - -# See https://github.com/rust-lang/rustfmt/blob/master/Configurations.md -# for more configuration options - -comment_width = 72 # Maximum line width for comments -doc_comment_code_block_width = 72 # Maximum line width for code blocks in doc comments -edition = "2021" # Use a single edition only (Edition 2018 or Edition 2021) -empty_item_single_line = true # Put empty items on a single line -force_explicit_abi = true # Force explicit abi -format_code_in_doc_comments = true # Format code snippets in doc comments -format_macro_bodies = true # Format macro bodies -format_macro_matchers = true # Format macro matchers -group_imports = "StdExternalCrate" # Group imports by crate -hard_tabs = false # Use spaces instead of tabs -imports_granularity = "Module" # Group imports by module -imports_layout = "HorizontalVertical" # Layout imports horizontally and vertically -max_width = 72 # Maximum line width -merge_derives = true # Merge derives -newline_style = "Unix" # Prevent carriage returns from being added to the end of lines -normalize_comments = true # Normalize comments -normalize_doc_attributes = true # Normalize doc attributes -overflow_delimited_expr = true # Allow overflowing delimited expressions -remove_nested_parens = true # Remove nested parens -reorder_imports = true # Reorder imports -reorder_modules = true # Reorder modules -tab_spaces = 4 # Use 4 spaces for indentation -use_field_init_shorthand = true # Use field initialization shorthand when possible -use_small_heuristics = "Max" # Use max heuristics -use_try_shorthand = true # Use try shorthand when possible -wrap_comments = true # Wrap comments when line width exceeds max max_width diff --git a/output_dir/src/lib.rs b/output_dir/src/lib.rs deleted file mode 100644 index 2a0cd83..0000000 --- a/output_dir/src/lib.rs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright notice and licensing information. -// These lines indicate the copyright of the software and its licensing terms. -// Copyright ยฉ 2024 test_lib. All rights reserved. -// SPDX-License-Identifier: MIT -//! -//! # `test_lib` ๐Ÿฆ€ -//! -//! [![test_lib](https://via.placeholder.com/1500x500.png/000000/FFFFFF?text=test_lib)](https://example.com "test_lib - A test library") -//! -//! A test library -//! -//! [![Crates.io](https://img.shields.io/crates/v/test_lib.svg?style=for-the-badge&color=success&labelColor=27A006)](https://crates.io/crates/test_lib "Crates.io") -//! [![Lib.rs](https://img.shields.io/badge/lib.rs-v0.1.0-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://lib.rs/crates/test_lib "Lib.rs") -//! [![License](https://img.shields.io/crates/l/test_lib.svg?style=for-the-badge&color=007EC6&labelColor=03589B)](MIT "MIT") -//! [![Rust](https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust)](https://www.rust-lang.org "Rust") -//! -//! ## Overview -//! -//! A test library -//! -//! ## Features -//! -//! - ... -//! - ... -//! - ... -//! -//! ## Usage -//! -//! Add the following to your `Cargo.toml` file: -//! -//! ```toml -//! [dependencies] -//! test_lib = "0.1.0" -//! serde = { version = "1.0", features = ["derive"] } -//! serde_json = "1.0" -//! ``` -//! -//! ## Examples -//! -//! Check out the examples folder for helpful snippets of code that -//! demonstrate how to use the `test_lib` library. You can also check out -//! the [documentation](https://docs.rs/test_lib) for more information on -//! how to use the library. -//! -//! ```rust -//! use test_lib::test_lib; -//! -//! ``` -//! -//! ## License -//! -//! The project is licensed under the terms of the MIT license. -//! -#![cfg_attr(feature = "bench", feature(test))] -#![deny(dead_code)] -#![deny(missing_debug_implementations)] -#![deny(missing_docs)] -#![forbid(unsafe_code)] -#![warn(unreachable_pub)] -#![doc( - html_favicon_url = "", - html_logo_url = "", - html_root_url = "https://docs.rs/test_lib" -)] -#![crate_name = "test_lib"] -#![crate_type = "lib"] - -/// The `loggers` module contains the loggers for the library. -pub mod loggers; - -/// The `macros` module contains functions for generating macros. -pub mod macros; - -use serde::{Deserialize, Serialize}; -use std::error::Error; - -#[non_exhaustive] -#[derive( - Clone, - Debug, - Deserialize, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, -)] - -#[allow(non_camel_case_types)] -/// test_lib is a data structure that ... -pub struct test_lib { - // Add any data fields needed here -} - -/// This is the main entry point for the test_lib library. -pub fn run() -> Result<(), Box> { - // Add your code here - let name = "test_lib"; - println!("Hello, {}!", { name }.to_uppercase()); - Ok(()) -} - - -impl test_lib { - /// Creates a new instance of test_lib - pub fn new() -> Self { - Self { - // Initialize any data fields here - } - } -} - -impl Default for test_lib { - /// Creates a new instance of test_lib with default values - fn default() -> Self { - Self::new() - } -} diff --git a/output_dir/src/loggers.rs b/output_dir/src/loggers.rs deleted file mode 100644 index 1e5965b..0000000 --- a/output_dir/src/loggers.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright notice and licensing information. -// These lines indicate the copyright of the software and its licensing terms. -// Copyright ยฉ 2024 test_lib. All rights reserved. -// SPDX-License-Identifier: MIT - -//! Application logging functionality -//! -//! Provides access to logging functions and types. -//! -use env_logger::Env; -use rlg::LogLevel; -use std::io::Write; - -/// Initializes the logging system. -/// -/// This function sets up the logging system using the `env_logger` crate. It takes a `default_log_level` parameter, which determines the minimum log level to be displayed. The function returns a `Result` type, which will be `Ok` if the logging system is initialized successfully, or an error if there was a problem. -/// -/// # Examples -/// -/// ``` -/// use rlg::LogLevel; -/// use test_lib::loggers::init_logger; -/// -/// // Initialize the logging system with a default log level of `info` -/// init_logger(Some(LogLevel::INFO)).unwrap(); -/// ``` -pub fn init_logger( - default_log_level: Option, -) -> Result<(), Box> { - let env = Env::default().default_filter_or( - default_log_level.unwrap_or(LogLevel::INFO).to_string(), - ); - - env_logger::Builder::from_env(env) - .format(|buf, record| { - writeln!(buf, "[{}] - {}", record.level(), record.args()) - }) - .init(); - - Ok(()) -} diff --git a/output_dir/src/macros.rs b/output_dir/src/macros.rs deleted file mode 100644 index e30f2be..0000000 --- a/output_dir/src/macros.rs +++ /dev/null @@ -1,120 +0,0 @@ -//! # Macros for the `test_lib` crate. -//! -//! This crate provides the following macros: -//! -//! - `test_lib`: The main macro for the `test_lib` crate. -//! - `test_lib_print`: Prints the arguments to the console. -//! - `test_lib_vec`: Creates a new vector of the given elements. -//! - `test_lib_map`: Creates a new map of the given key-value pairs. -//! - `test_lib_assert`: Checks if the given expression is true. -//! - `test_lib_min`: Returns the minimum of the given values. -//! - `test_lib_max`: Returns the maximum of the given values. -//! - `test_lib_split`: Splits a string into a vector of words. -//! - `test_lib_join`: Joins a vector of strings into a single string. -//! - `test_lib_print_vec`: Prints a vector of elements to the console. -//! - -/// This macro takes any number of arguments and parses them into a -/// Rust value. -#[macro_export] -macro_rules! test_lib { - ($($tt:tt)*) => { - // Parse the arguments into a Rust value. - $crate::parse!($($tt)*) - }; -} - -/// This macro prints the arguments to the console. -#[macro_export] -macro_rules! test_lib_print { - ($($arg:tt)*) => { - println!("{}", format_args!("{}", $($arg)*)); - }; -} - -/// This macro creates a new vector of the given elements. -#[macro_export] -macro_rules! test_lib_vec { - ($($elem:expr),*) => {{ - let mut v = Vec::new(); - $(v.push($elem);)* - v - }}; -} - -/// This macro creates a new map of the given key-value pairs. -#[macro_export] -macro_rules! test_lib_map { - ($($key:expr => $value:expr),*) => {{ - use std::collections::HashMap; - let mut m = HashMap::new(); - $(m.insert($key, $value);)* - m - }}; -} - -/// This macro checks if the given expression is true. -#[macro_export] -macro_rules! test_lib_assert { - ($($arg:tt)*) => { - if !$($arg)* { - panic!("Assertion failed!"); - } - }; -} - -/// This macro returns the minimum of the given values. -#[macro_export] -macro_rules! test_lib_min { - ($($x:expr),*) => {{ - let mut min = $($x)*; - $(if min > $x { min = $x; })* - min - }}; -} - -/// This macro returns the maximum of the given values. -#[macro_export] -macro_rules! test_lib_max { - ($($x:expr),*) => {{ - let mut max = $($x)*; - $(if max < $x { max = $x; })* - max - }}; -} - -/// This macro takes a string and splits it into a vector of words. -#[macro_export] -macro_rules! test_lib_split { - ($s:expr) => {{ - let mut v = Vec::new(); - for w in $s.split_whitespace() { - v.push(w.to_string()); - } - v - }}; -} - -/// This macro takes a vector of strings and joins them together into a -/// single string. -#[macro_export] -macro_rules! test_lib_join { - ($($s:expr),*) => {{ - let mut s = String::new(); - $( - s += &$s; - )* - s - }}; -} - -/// This macro takes a vector of elements and prints them to the -/// console. -#[macro_export] -macro_rules! test_lib_print_vec { - ($($v:expr),*) => {{ - for v in $($v),* { - println!("{}", v); - } - }}; -} diff --git a/output_dir/src/main.rs b/output_dir/src/main.rs deleted file mode 100644 index 38c0789..0000000 --- a/output_dir/src/main.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright notice and licensing information. -// These lines indicate the copyright of the software and its licensing terms. -// Copyright ยฉ 2024 test_lib. All rights reserved. -// SPDX-License-Identifier: MIT - -/// This is the main entry point for the test_lib application. -fn main() { - // Call the `run()` function from the `test_lib` module. - if let Err(err) = test_lib::run() { - eprintln!("Error running test_lib: {}", err); - std::process::exit(1); - } -} diff --git a/output_dir/tests/test.rs b/output_dir/tests/test.rs deleted file mode 100644 index 5cf298a..0000000 --- a/output_dir/tests/test.rs +++ /dev/null @@ -1,11 +0,0 @@ -#[cfg(test)] -mod tests { - - use test_lib::test_lib; - - #[test] - fn test_test_lib() { - let test_lib = test_lib::new(); - assert_eq!(test_lib, test_lib::default()); - } -} diff --git a/output_dir/tests/test_loggers.rs b/output_dir/tests/test_loggers.rs deleted file mode 100644 index 7a75912..0000000 --- a/output_dir/tests/test_loggers.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright notice and licensing information. -// These lines indicate the copyright of the software and its licensing terms. -// Copyright ยฉ 2024 test_lib. All rights reserved. -// SPDX-License-Identifier: MIT - -#[cfg(test)] -mod tests { - - use rlg::macro_log; - use rlg::{LogFormat, LogLevel}; - - #[test] - fn test_logging() { - // Create a log entry - let log_entry = - macro_log!( - "session_id", - "time", - &LogLevel::INFO, - "component", - "Log message", - &LogFormat::CLF - ); - - // Define expected values - let expected_session_id = "session_id"; - let expected_time = "time"; - let expected_level = LogLevel::INFO; - let expected_component = "component"; - let expected_description = "Log message"; - let expected_format = LogFormat::CLF; - - // Assert that individual fields match the expected values - assert_eq!(log_entry.session_id, expected_session_id); - assert_eq!(log_entry.time, expected_time); - assert_eq!(log_entry.level, expected_level); - assert_eq!(log_entry.component, expected_component); - assert_eq!(log_entry.description, expected_description); - assert_eq!(log_entry.format, expected_format); - } -} diff --git a/src/args.rs b/src/args.rs index e8cb07f..86d47a0 100644 --- a/src/args.rs +++ b/src/args.rs @@ -4,14 +4,18 @@ // Copyright ยฉ 2024 LibMake. All rights reserved. use super::{ + generate_file, extract_param, - generator::{ - generate_files, generate_from_csv, generate_from_ini, - generate_from_json, generate_from_toml, generate_from_yaml, - FileGenerationParams, - }, + generator::generate_files, + generators::csv::generate_from_csv, + generators::ini::generate_from_ini, + generators::json::generate_from_json, + generators::toml::generate_from_toml, + generators::yaml::generate_from_yaml, + models::model_params::FileGenerationParams, }; use clap::ArgMatches; +use regex::Regex; use std::error::Error; /// Processes the command line arguments provided to the program. @@ -20,56 +24,40 @@ use std::error::Error; /// /// # Arguments /// -/// * `matches` - An instance of `clap::ArgMatches` containing the -/// parsed command line arguments. +/// * `matches` - An instance of `clap::ArgMatches` containing the parsed command line arguments. /// /// # Errors /// /// This function will return an error if there is an issue with processing the command line arguments or generating files. -/// -/// # Panics -/// -/// This function may panic if a required command line argument is not provided. -pub fn process_arguments( - matches: &ArgMatches, -) -> Result<(), Box> { +pub fn process_arguments(matches: &ArgMatches) -> Result<(), Box> { match matches.subcommand() { Some(("file", file_matches)) => { - let file_types = ["csv", "ini", "json", "yaml", "toml"]; - - for file_type in file_types.iter() { - if let Some(value) = - file_matches.get_one::(file_type) - { - match *file_type { - "csv" if !value.trim().is_empty() => { - generate_from_csv(value)? - } - "ini" if !value.trim().is_empty() => { - generate_from_ini(value)? - } - "json" if !value.trim().is_empty() => { - generate_from_json(value)? - } - "yaml" if !value.trim().is_empty() => { - generate_from_yaml(value)? - } - "toml" if !value.trim().is_empty() => { - generate_from_toml(value)? - } - _ => {} - } - } + if let Some(value) = file_matches.get_one::("csv") { + generate_file!("csv", value, generate_from_csv); + } + if let Some(value) = file_matches.get_one::("ini") { + generate_file!("ini", value, generate_from_ini); + } + if let Some(value) = file_matches.get_one::("json") { + generate_file!("json", value, generate_from_json); + } + if let Some(value) = file_matches.get_one::("yaml") { + generate_file!("yaml", value, generate_from_yaml); + } + if let Some(value) = file_matches.get_one::("toml") { + generate_file!("toml", value, generate_from_toml); } } Some(("manual", manual_matches)) => { let params = extract_manual_params(manual_matches)?; - generate_files(params)?; - println!("Template files generated successfully!"); + if let Err(err) = generate_files(params) { + eprintln!("Error generating template files: {}", err); + } else { + println!("Template files generated successfully!"); + } } _ => { eprintln!("No valid subcommand was used. Please use '--help' for usage information."); - std::process::exit(1); } } @@ -104,59 +92,76 @@ pub fn extract_manual_params( } /// Validates the manual generation parameters. -pub fn validate_params( - params: &FileGenerationParams, -) -> Result<(), Box> { +pub fn validate_params(params: &FileGenerationParams) -> Result<(), Box> { if params.name.is_none() { return Err("The name of the library is required for manual generation.".into()); } if params.output.is_none() { - return Err( - "The output directory is required for manual generation." - .into(), - ); + return Err("The output directory is required for manual generation.".into()); } if let Some(edition) = ¶ms.edition { - if edition != "2015" && edition != "2018" && edition != "2021" { - return Err(format!("Invalid edition: {}. Supported editions are 2015, 2018, and 2021.", edition).into()); + let valid_editions = ["2015", "2018", "2021"]; + if !valid_editions.contains(&edition.as_str()) { + return Err(format!( + "Invalid edition: {}. Supported editions are: {}.", + edition, + valid_editions.join(", ") + ) + .into()); } } if let Some(rustversion) = ¶ms.rustversion { - if !rustversion.starts_with("1.") { - return Err(format!("Invalid Rust version: {}. Rust version should start with '1.'.", rustversion).into()); + let version_regex = Regex::new(r"^1\.\d+\.\d+$").unwrap(); + if !version_regex.is_match(rustversion) { + return Err(format!( + "Invalid Rust version: {}. Rust version should be in the format '1.x.y'.", + rustversion + ) + .into()); } } if let Some(email) = ¶ms.email { - if !email.contains('@') { - return Err(format!("Invalid email address: {}. Email address should contain '@'.", email).into()); + let email_regex = Regex::new(r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$").unwrap(); + if !email_regex.is_match(email) { + return Err(format!("Invalid email address: {}.", email).into()); } } if let Some(repository) = ¶ms.repository { - if !repository.starts_with("https://") - && !repository.starts_with("git://") - { - return Err(format!("Invalid repository URL: {}. Repository URL should start with 'https://' or 'git://'.", repository).into()); + let repo_regex = + Regex::new(r"^(https://|git://|ssh://|git@).+\.git$").unwrap(); + if !repo_regex.is_match(repository) { + return Err(format!( + "Invalid repository URL: {}. Repository URL should be a valid Git URL.", + repository + ) + .into()); } } if let Some(homepage) = ¶ms.homepage { - if !homepage.starts_with("http://") - && !homepage.starts_with("https://") - { - return Err(format!("Invalid homepage URL: {}. Homepage URL should start with 'http://' or 'https://'.", homepage).into()); + let url_regex = Regex::new(r"^(http://|https://).+$").unwrap(); + if !url_regex.is_match(homepage) { + return Err(format!( + "Invalid homepage URL: {}. Homepage URL should start with 'http://' or 'https://'.", + homepage + ) + .into()); } } if let Some(documentation) = ¶ms.documentation { - if !documentation.starts_with("http://") - && !documentation.starts_with("https://") - { - return Err(format!("Invalid documentation URL: {}. Documentation URL should start with 'http://' or 'https://'.", documentation).into()); + let url_regex = Regex::new(r"^(http://|https://).+$").unwrap(); + if !url_regex.is_match(documentation) { + return Err(format!( + "Invalid documentation URL: {}. Documentation URL should start with 'http://' or 'https://'.", + documentation + ) + .into()); } } diff --git a/src/cli.rs b/src/cli.rs index d4c58bc..09b1fbf 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -38,7 +38,7 @@ pub fn build() -> Result { create_arg_info("readme", Some("README.md"), "Sets the README file for the library", 'm', "readme", "README"), create_arg_info("repository", Some("https://github.com/example/my_library"), "Sets the repository URL of the library", 'g', "repository", "REPOSITORY"), create_arg_info("rustversion", Some("1.75.0"), "Sets the Rust version of the library", 'r', "rustversion", "RUSTVERSION"), - create_arg_info("version", Some("0.2.2"), "Sets the version of the library", 'v', "version", "VERSION"), + create_arg_info("version", Some("0.2.3"), "Sets the version of the library", 'v', "version", "VERSION"), create_arg_info("website", Some("https://test.com"), "Sets the website of the library author", 'w', "website", "WEBSITE"), ]; diff --git a/src/generator.rs b/src/generator.rs index 8cf741d..d69066f 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -3,206 +3,15 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. // Copyright ยฉ 2024 LibMake. All rights reserved. -use super::interface::replace_placeholders; -use serde::{Deserialize, Serialize}; -use std::{ - fs, io, - path::{Path, PathBuf}, +use crate::{ + interface::replace_placeholders, macro_generate_from_csv, + macro_generate_from_ini, macro_generate_from_json, + macro_generate_from_toml, macro_generate_from_yaml, + models::model_params::FileGenerationParams, + utils::create_directory, }; +use std::{fs, io, path::PathBuf}; -/// Structure for holding the parameters for generating the project files. -/// -/// # Description -/// -/// * The `output` directory is the directory where the project files will be created. -/// * The other parameters are optional and will be used to replace the placeholders in the template files. -/// * The template files are located in the template directory of the project. -/// * The template files are copied to the output directory and the placeholders are replaced with the values of the parameters. -/// -#[derive( - Clone, - Debug, - Default, - Deserialize, - Eq, - Hash, - Ord, - PartialEq, - PartialOrd, - Serialize, -)] -pub struct FileGenerationParams { - /// The author of the project (optional). - pub author: Option, - /// The build command to be used for building the project (optional). - pub build: Option, - /// The categories that the project belongs to (optional). - pub categories: Option, - /// A short description of the project (optional). - pub description: Option, - /// The documentation URL of the project (optional). - pub documentation: Option, - /// The edition of the project (optional). - pub edition: Option, - /// The email address of the author (optional). - pub email: Option, - /// The homepage of the project (optional). - pub homepage: Option, - /// Keywords that describe the project (optional). - pub keywords: Option, - /// The license under which the project is released (optional). - pub license: Option, - /// The name of the project (optional). - pub name: Option, - /// The output directory where the project files will be created (optional). - pub output: Option, - /// The name of the readme file (optional). - pub readme: Option, - /// The URL of the project's repository (optional). - pub repository: Option, - /// The minimum Rust version required by the project (optional). - pub rustversion: Option, - /// The initial version of the project (optional). - pub version: Option, - /// The website of the project (optional). - pub website: Option, -} - -impl FileGenerationParams { - /// Creates a default instance with default values for all fields. - /// Fields that are truly optional without a default are initialized as `None`. - pub fn default_params() -> Self { - Self { - author: Some("John Smith".to_string()), - build: Some("build.rs".to_string()), - categories: Some( - "[\"category1\",\"category2\",\"category3\"]" - .to_string(), - ), - description: Some( - "A Rust library for doing cool things".to_string(), - ), - documentation: Some( - "https://docs.rs/my_library".to_string(), - ), - edition: Some("2021".to_string()), - email: Some("john.smith@example.com".to_string()), - homepage: Some("https://my_library.rs".to_string()), - keywords: Some( - "[\"rust\",\"library\",\"cool\"]".to_string(), - ), - license: Some("MIT".to_string()), - name: Some("my_library".to_string()), - output: Some("my_library".to_string()), - readme: Some("README.md".to_string()), - repository: Some( - "https://github.com/example/my_library".to_string(), - ), - rustversion: Some("1.75.0".to_string()), - version: Some("0.1.0".to_string()), - website: Some("https://example.com/john-smith".to_string()), - } - } - /// Parses the command line arguments and returns a new instance of - /// the structure. - - /// Creates a new instance with default values. - pub fn new() -> Self { - Self::default_params() - } - /// Parses the command line arguments and returns a new instance of - /// the structure. - /// - /// # Arguments - /// * `args_str` - A string slice containing the command line arguments. - /// - /// # Errors - /// Returns an `Err` if the arguments are not in the expected format - /// or if mandatory arguments are missing. The error is a `String` - /// describing what went wrong. - /// - pub fn from_args(args_str: &str) -> Result { - let mut params = Self::new(); - let args: Vec<&str> = args_str.split_whitespace().collect(); - for arg in args { - let mut arg_parts = arg.splitn(2, ' '); - let arg_name = arg_parts - .next() - .ok_or_else(|| "Missing argument name".to_string())?; - let arg_value = arg_parts - .next() - .ok_or_else(|| "Missing argument value".to_string())?; - match arg_name { - "--author" => { - params.author = Some(arg_value.to_string()); - } - "--build" => params.build = Some(arg_value.to_string()), - "--categories" => { - params.categories = Some(arg_value.to_string()); - } - "--description" => { - params.description = Some(arg_value.to_string()); - } - "--documentation" => { - params.documentation = Some(arg_value.to_string()); - } - "--edition" => { - params.edition = Some(arg_value.to_string()); - } - "--email" => params.email = Some(arg_value.to_string()), - "--homepage" => { - params.homepage = Some(arg_value.to_string()); - } - "--keywords" => { - params.keywords = Some(arg_value.to_string()); - } - "--license" => { - params.license = Some(arg_value.to_string()); - } - "--name" => params.name = Some(arg_value.to_string()), - "--output" => { - params.output = Some(arg_value.to_string()); - } - "--readme" => { - params.readme = Some(arg_value.to_string()); - } - "--repository" => { - params.repository = Some(arg_value.to_string()); - } - "--rustversion" => { - params.rustversion = Some(arg_value.to_string()); - } - "--version" => { - params.version = Some(arg_value.to_string()); - } - "--website" => { - params.website = Some(arg_value.to_string()); - } - _ => (), - } - } - Ok(params) - } -} - -/// Creates a directory at the specified path. -/// -/// # Arguments -/// -/// * `path` - The path where the directory should be created. -/// -/// # Errors -/// -/// Returns an `io::Error` if the directory cannot be created. This could be due to -/// various reasons such as insufficient permissions, the directory already existing, -/// or other I/O-related errors. -/// -pub fn create_directory(path: &Path) -> io::Result<()> { - fs::create_dir(path).or_else(|e| match e.kind() { - io::ErrorKind::AlreadyExists => Ok(()), - _ => Err(e), - }) -} /// Creates the template folder and downloads necessary template files. /// /// This function attempts to create a template directory in the current working directory @@ -233,14 +42,12 @@ pub fn create_template_folder() -> io::Result<()> { "example.tpl", "gitignore.tpl", "lib.tpl", - "loggers.tpl", "macros.tpl", "main.tpl", "README.tpl", "rustfmt.tpl", "TEMPLATE.tpl", "test.tpl", - "test_loggers.tpl", ]; for file in &files { let file_path = template_dir_path.join(file); @@ -294,8 +101,6 @@ pub fn create_template_folder() -> io::Result<()> { /// - If the destination file cannot be created or written to. /// - If there is an error in replacing placeholders in the destination file. /// -/// The specific error will provide more details about what went wrong. -/// pub fn copy_and_replace_template( template_file: &str, dest_file: &str, @@ -339,7 +144,10 @@ pub fn generate_files(params: FileGenerationParams) -> io::Result<()> { )); }; - let project_directory = PathBuf::from(output.clone()); + // Get the project directory path from the output parameter, + // create a PathBuf from it, and assign it to the project_directory variable + let project_directory = + PathBuf::from(output.clone().trim_matches('\"')); // Creating the project directory create_directory(&project_directory)?; @@ -376,13 +184,11 @@ pub fn generate_files(params: FileGenerationParams) -> io::Result<()> { ("example.tpl", "examples/example.rs"), ("gitignore.tpl", ".gitignore"), ("lib.tpl", "src/lib.rs"), - ("loggers.tpl", "src/loggers.rs"), ("macros.tpl", "src/macros.rs"), ("main.tpl", "src/main.rs"), ("README.tpl", "README.md"), ("rustfmt.tpl", "rustfmt.toml"), ("TEMPLATE.tpl", "TEMPLATE.md"), - ("test_loggers.tpl", "tests/test_loggers.rs"), ("test.tpl", "tests/test.rs"), ]; @@ -451,7 +257,7 @@ pub fn generate_files(params: FileGenerationParams) -> io::Result<()> { /// # Arguments /// /// - `path` - The path to the configuration file. -/// - `file_type` - The type of the configuration file (e.g., JSON, YAML, CSV). +/// - `file_type` - The type of the configuration file (e.g., JSON, YAML, CSV, TOML and INI). /// /// # Errors /// @@ -464,310 +270,20 @@ pub fn generate_files(params: FileGenerationParams) -> io::Result<()> { pub fn generate_from_config( path: &str, file_type: &str, -) -> io::Result<()> { +) -> Result<(), String> { match file_type { - "csv" => generate_from_csv(path), - "ini" => generate_from_ini(path), - "json" => generate_from_json(path), - "yaml" => generate_from_yaml(path), - "toml" => generate_from_toml(path), - _ => Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Invalid configuration file format. Supported formats: CSV, INI, JSON, TOML, YAML.", - )), - } -} - -/// Generates files for a new Rust project based on a CSV file. -/// -/// # Arguments -/// -/// The CSV file must contain the following columns: -/// -/// - `author` - the author of the project (optional). -/// - `build` - the build command to be used for building the project (optional). -/// - `categories` - the categories that the project belongs to (optional). -/// - `description` - a short description of the project (optional). -/// - `documentation` - the documentation URL of the project (optional). -/// - `edition` - the edition of the project (optional). -/// - `email` - the email address of the author (optional). -/// - `homepage` - the homepage of the project (optional). -/// - `keywords` - keywords that describe the project (optional). -/// - `license` - the license under which the project is released (optional). -/// - `name` - the name of the project (optional). -/// - `output` - the output directory where the project files will be created (required). -/// - `readme` - the name of the readme file (optional). -/// - `repository` - the url of the project's repository (optional). -/// - `rustversion` - the minimum Rust version required by the project (optional). -/// - `version` - the initial version of the project (optional). -/// - `website` - the website of the project (optional). -/// -/// # Errors -/// -/// This function will return an error in the following situations: -/// -/// - If the specified CSV file cannot be found, read, or is not valid CSV. -/// - If an error occurs while parsing the CSV data into the `FileGenerationParams` struct. -/// - If there is an error in generating files based on the parameters from each CSV record. -/// -pub fn generate_from_csv(path: &str) -> io::Result<()> { - let mut reader = csv::Reader::from_path(path)?; - for result in reader.records() { - let record = result?; - // println!("{:?}", record); - let params = FileGenerationParams { - author: record.get(0).map(ToString::to_string), - build: record.get(1).map(ToString::to_string), - categories: record.get(2).map(ToString::to_string), - description: record.get(3).map(ToString::to_string), - documentation: record.get(4).map(ToString::to_string), - edition: record.get(5).map(ToString::to_string), - email: record.get(6).map(ToString::to_string), - homepage: record.get(7).map(ToString::to_string), - keywords: record.get(8).map(ToString::to_string), - license: record.get(9).map(ToString::to_string), - name: record.get(10).map(ToString::to_string), - output: record.get(11).map(ToString::to_string), - readme: record.get(12).map(ToString::to_string), - repository: record.get(13).map(ToString::to_string), - rustversion: record.get(14).map(ToString::to_string), - version: record.get(15).map(ToString::to_string), - website: record.get(16).map(ToString::to_string), - }; - // println!("Params: {:?}", params); - generate_files(params)?; - } - Ok(()) -} - -/// Generates files for a new Rust project based on a JSON file. -/// -/// # Arguments -/// -/// The JSON file must contain a single object with the following -/// properties: -/// -/// - `author` - the author of the project (optional). -/// - `build` - the build command to be used for building the project (optional). -/// - `categories` - the categories that the project belongs to (optional). -/// - `description` - a short description of the project (optional). -/// - `documentation` - the documentation URL of the project (optional). -/// - `edition` - the edition of the project (optional). -/// - `email` - the email address of the author (optional). -/// - `homepage` - the homepage of the project (optional). -/// - `keywords` - keywords that describe the project (optional). -/// - `license` - the license under which the project is released (optional). -/// - `name` - the name of the project (optional). -/// - `output` - the output directory where the project files will be created (required). -/// - `readme` - the name of the readme file (optional). -/// - `repository` - the url of the project's repository (optional). -/// - `rustversion` - the minimum Rust version required by the project (optional). -/// - `version` - the initial version of the project (optional). -/// - `website` - the website of the project (optional). -/// -/// # Errors -/// -/// This function will return an error in the following situations: -/// -/// - If the specified JSON file cannot be found, read, or is not valid UTF-8. -/// - If the JSON data cannot be deserialized into the `FileGenerationParams` struct. -/// - If there is an error in generating files based on the parameters. -/// -pub fn generate_from_json(path: &str) -> io::Result<()> { - let contents = fs::read_to_string(path)?; - let params: FileGenerationParams = serde_json::from_str(&contents)?; - generate_files(params)?; - Ok(()) -} - -/// Generates files for a new Rust project based on a YAML file. -/// -/// The YAML file must contain a single object with the following -/// properties: -/// -/// - `author` - the author of the project (optional). -/// - `build` - the build command to be used for building the project (optional). -/// - `categories` - the categories that the project belongs to (optional). -/// - `description` - a short description of the project (optional). -/// - `documentation` - the documentation URL of the project (optional). -/// - `edition` - the edition of the project (optional). -/// - `email` - the email address of the author (optional). -/// - `homepage` - the homepage of the project (optional). -/// - `keywords` - keywords that describe the project (optional). -/// - `license` - the license under which the project is released (optional). -/// - `name` - the name of the project (optional). -/// - `output` - the output directory where the project files will be created (required). -/// - `readme` - the name of the readme file (optional). -/// - `repository` - the url of the project's repository (optional). -/// - `rustversion` - the minimum Rust version required by the project (optional). -/// - `version` - the initial version of the project (optional). -/// - `website` - the website of the project (optional). -/// -/// # Errors -/// -/// This function will return an error in the following situations: -/// -/// - If the specified YAML file cannot be found, read, or is not valid UTF-8. -/// - If the YAML data cannot be deserialized into the `FileGenerationParams` struct. -/// - If there is an error in generating files based on the parameters. -/// -pub fn generate_from_yaml(path: &str) -> io::Result<()> { - let contents = fs::read_to_string(path)?; - let params: FileGenerationParams = serde_yaml::from_str(&contents) - .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; - generate_files(params)?; - Ok(()) -} - -/// Generates files for a new Rust project based on an INI file. -/// -/// The INI file must contain a single section with the following -/// keys: -/// - `author` - the author of the project (optional). -/// - `build` - the build command to be used for building the project (optional). -/// - `categories` - the categories that the project belongs to (optional). -/// - `description` - a short description of the project (optional). -/// - `documentation` - the documentation URL of the project (optional). -/// - `edition` - the edition of the project (optional). -/// - `email` - the email address of the author (optional). -/// - `homepage` - the homepage of the project (optional). -/// - `keywords` - keywords that describe the project (optional). -/// - `license` - the license under which the project is released (optional). -/// - `name` - the name of the project (optional). -/// - `output` - the output directory where the project files will be created (required). -/// - `readme` - the name of the readme file (optional). -/// - `repository` - the url of the project's repository (optional). -/// - `rustversion` - the minimum Rust version required by the project (optional). -/// - `version` - the initial version of the project (optional). -/// - `website` - the website of the project (optional). -/// -/// # Errors -/// -/// This function will return an error in the following situations: -/// -/// - If the specified INI file cannot be found, read, or is not valid UTF-8. -/// - If the INI data cannot be parsed into the `FileGenerationParams` struct. -/// - If there is an error in generating files based on the parameters. -/// -pub fn generate_from_ini(path: &str) -> io::Result<()> { - let contents = fs::read_to_string(path)?; - let params: FileGenerationParams = toml::from_str(&contents) - .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; - generate_files(params)?; - Ok(()) -} - -/// Generates files for a new Rust project based on a TOML file. -/// -/// The TOML file must contain a single object with the following -/// properties: -/// -/// - `author` - the author of the project (optional). -/// - `build` - the build command to be used for building the project (optional). -/// - `categories` - the categories that the project belongs to (optional). -/// - `description` - a short description of the project (optional). -/// - `documentation` - the documentation URL of the project (optional). -/// - `edition` - the edition of the project (optional). -/// - `email` - the email address of the author (optional). -/// - `homepage` - the homepage of the project (optional). -/// - `keywords` - keywords that describe the project (optional). -/// - `license` - the license under which the project is released (optional). -/// - `name` - the name of the project (optional). -/// - `output` - the output directory where the project files will be created (required). -/// - `readme` - the name of the readme file (optional). -/// - `repository` - the url of the project's repository (optional). -/// - `rustversion` - the minimum Rust version required by the project (optional). -/// - `version` - the initial version of the project (optional). -/// - `website` - the website of the project (optional). -/// -/// # Errors -/// -/// This function will return an error in the following situations: -/// -/// - If the specified TOML file cannot be found, read, or is not valid UTF-8. -/// - If the TOML data cannot be deserialized into the `FileGenerationParams` struct. -/// - If there is an error in generating files based on the parameters. -/// -pub fn generate_from_toml(path: &str) -> io::Result<()> { - let contents = fs::read_to_string(path)?; - let params: FileGenerationParams = toml::from_str(&contents) - .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; - generate_files(params)?; - Ok(()) -} - -/// Generates files for a new Rust project based on command line arguments. -/// The arguments must be in the form `--name=value`. -/// The following arguments are supported: -/// - `author` - the author of the project (optional). -/// - `build` - the build command to be used for building the project (optional). -/// - `categories` - the categories that the project belongs to (optional). -/// - `description` - a short description of the project (optional). -/// - `documentation` - the documentation URL of the project (optional). -/// - `edition` - the edition of the project (optional). -/// - `email` - the email address of the author (optional). -/// - `homepage` - the homepage of the project (optional). -/// - `keywords` - keywords that describe the project (optional). -/// - `license` - the license under which the project is released (optional). -/// - `name` - the name of the project (optional). -/// - `output` - the output directory where the project files will be created (required). -/// - `readme` - the name of the readme file (optional). -/// - `repository` - the url of the project's repository (optional). -/// - `rustversion` - the minimum Rust version required by the project (optional). -/// - `version` - the initial version of the project (optional). -/// - `website` - the website of the project (optional). -/// -/// # Errors -/// -/// This function will return an error in the following situations: -/// -/// - If an invalid argument is provided. Each argument must be in the form `--name=value`. -/// - If there is an error in generating files based on the parameters derived from the arguments. -/// -pub fn generate_from_args(args_str: &str) -> io::Result<()> { - let args = args_str.split_whitespace(); - let mut params = FileGenerationParams::default(); - for arg in args { - let mut parts = arg.splitn(2, '='); - let name = parts.next().unwrap_or_default(); - let value = parts.next().unwrap_or_default(); - match name { - "--author" => params.author = Some(value.to_string()), - "--build" => params.build = Some(value.to_string()), - "--categories" => { - params.categories = Some(value.to_string()); - } - "--description" => { - params.description = Some(value.to_string()); - } - "--documentation" => { - params.documentation = Some(value.to_string()); - } - "--edition" => params.edition = Some(value.to_string()), - "--email" => params.email = Some(value.to_string()), - "--homepage" => params.homepage = Some(value.to_string()), - "--keywords" => params.keywords = Some(value.to_string()), - "--license" => params.license = Some(value.to_string()), - "--name" => params.name = Some(value.to_string()), - "--output" => params.output = Some(value.to_string()), - "--readme" => params.readme = Some(value.to_string()), - "--repository" => { - params.repository = Some(value.to_string()); - } - "--rustversion" => { - params.rustversion = Some(value.to_string()); - } - "--version" => params.version = Some(value.to_string()), - "--website" => params.website = Some(value.to_string()), - _ => { - return Err(io::Error::new( - io::ErrorKind::Other, - format!("Invalid argument: {name}"), - )) - } + "csv" => macro_generate_from_csv!(path)?, + "ini" => macro_generate_from_ini!(path)?, + "json" => macro_generate_from_json!(path)?, + "yaml" => macro_generate_from_yaml!(path)?, + "toml" => macro_generate_from_toml!(path)?, + _ => { + return Err(format!( + "Unsupported configuration file type: {}", + file_type + )) } } - println!("{params:?}"); - generate_files(params)?; Ok(()) } + diff --git a/src/generators/args.rs b/src/generators/args.rs new file mode 100644 index 0000000..71f7217 --- /dev/null +++ b/src/generators/args.rs @@ -0,0 +1,81 @@ +use crate::{ + generator::generate_files, + models::model_params::FileGenerationParams, +}; +use std::io; + +/// Generates files for a new Rust project based on command line arguments. +/// The arguments must be in the form `--name=value`. +/// The following arguments are supported: +/// - `author` - the author of the project (optional). +/// - `build` - the build command to be used for building the project (optional). +/// - `categories` - the categories that the project belongs to (optional). +/// - `description` - a short description of the project (optional). +/// - `documentation` - the documentation URL of the project (optional). +/// - `edition` - the edition of the project (optional). +/// - `email` - the email address of the author (optional). +/// - `homepage` - the homepage of the project (optional). +/// - `keywords` - keywords that describe the project (optional). +/// - `license` - the license under which the project is released (optional). +/// - `name` - the name of the project (optional). +/// - `output` - the output directory where the project files will be created (required). +/// - `readme` - the name of the readme file (optional). +/// - `repository` - the url of the project's repository (optional). +/// - `rustversion` - the minimum Rust version required by the project (optional). +/// - `version` - the initial version of the project (optional). +/// - `website` - the website of the project (optional). +/// +/// # Errors +/// +/// This function will return an error in the following situations: +/// +/// - If an invalid argument is provided. Each argument must be in the form `--name=value`. +/// - If there is an error in generating files based on the parameters derived from the arguments. +/// +pub fn generate_from_args(args_str: &str) -> io::Result<()> { + let args = args_str.split_whitespace(); + let mut params = FileGenerationParams::default(); + for arg in args { + let mut parts = arg.splitn(2, '='); + let name = parts.next().unwrap_or_default(); + let value = parts.next().unwrap_or_default(); + match name { + "--author" => params.author = Some(value.to_string()), + "--build" => params.build = Some(value.to_string()), + "--categories" => { + params.categories = Some(value.to_string()); + } + "--description" => { + params.description = Some(value.to_string()); + } + "--documentation" => { + params.documentation = Some(value.to_string()); + } + "--edition" => params.edition = Some(value.to_string()), + "--email" => params.email = Some(value.to_string()), + "--homepage" => params.homepage = Some(value.to_string()), + "--keywords" => params.keywords = Some(value.to_string()), + "--license" => params.license = Some(value.to_string()), + "--name" => params.name = Some(value.to_string()), + "--output" => params.output = Some(value.to_string()), + "--readme" => params.readme = Some(value.to_string()), + "--repository" => { + params.repository = Some(value.to_string()); + } + "--rustversion" => { + params.rustversion = Some(value.to_string()); + } + "--version" => params.version = Some(value.to_string()), + "--website" => params.website = Some(value.to_string()), + _ => { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("Invalid argument: {name}"), + )) + } + } + } + println!("{params:?}"); + generate_files(params)?; + Ok(()) +} diff --git a/src/ascii.rs b/src/generators/ascii.rs similarity index 59% rename from src/ascii.rs rename to src/generators/ascii.rs index e850e7d..08118df 100644 --- a/src/ascii.rs +++ b/src/generators/ascii.rs @@ -6,28 +6,7 @@ //! This module provides functionality for generating ASCII art from text using the FIGlet library. use figlet_rs::FIGfont; -use std::error::Error; -use std::fmt; - -/// Error type for ASCII art generation failures. -#[derive(Debug)] -pub enum ArtError { - /// Represents a failure to load the FIGfont. - FontLoadError, - /// Represents a failure to convert text to ASCII art. - ConversionError, -} - -impl fmt::Display for ArtError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - Self::FontLoadError => write!(f, "Failed to load FIGfont"), - Self::ConversionError => write!(f, "Failed to convert text to ASCII art"), - } - } -} - -impl Error for ArtError {} +use crate::models::error_ascii_art::AsciiArtError; /// Generates ASCII art from the given text using the standard `FIGfont`. /// @@ -46,21 +25,22 @@ impl Error for ArtError {} /// # Examples /// /// ``` -/// use libmake::ascii::generate_ascii_art; +/// use libmake::generators::ascii::generate_ascii_art; /// /// let text = "Hello, world!"; /// let result = generate_ascii_art(text); /// assert!(result.is_ok()); /// ``` -pub fn generate_ascii_art(text: &str) -> Result { +pub fn generate_ascii_art(text: &str) -> Result { if text.is_empty() { - return Err(ArtError::ConversionError); + return Err(AsciiArtError::ConversionError); } let standard_font = load_standard_font()?; let figure = standard_font .convert(text) - .ok_or(ArtError::ConversionError)?; + .ok_or(AsciiArtError::ConversionError)?; + Ok(figure.to_string()) } @@ -73,11 +53,11 @@ pub fn generate_ascii_art(text: &str) -> Result { /// # Examples /// /// ``` -/// use libmake::ascii::load_standard_font; +/// use libmake::generators::ascii::load_standard_font; /// /// let result = load_standard_font(); /// assert!(result.is_ok()); /// ``` -pub fn load_standard_font() -> Result { - FIGfont::standard().map_err(|_| ArtError::FontLoadError) +pub fn load_standard_font() -> Result { + FIGfont::standard().map_err(|_| AsciiArtError::FontLoadError) } diff --git a/src/generators/csv.rs b/src/generators/csv.rs new file mode 100644 index 0000000..64dd32a --- /dev/null +++ b/src/generators/csv.rs @@ -0,0 +1,65 @@ +use std::io; +use csv::Reader; +use crate::models::model_params::FileGenerationParams; +use crate::macro_generate_files; + +/// Generates files for a new Rust project based on a CSV file. +/// +/// # Arguments +/// +/// The CSV file must contain the following columns: +/// +/// - `author` - the author of the project (optional). +/// - `build` - the build command to be used for building the project (optional). +/// - `categories` - the categories that the project belongs to (optional). +/// - `description` - a short description of the project (optional). +/// - `documentation` - the documentation URL of the project (optional). +/// - `edition` - the edition of the project (optional). +/// - `email` - the email address of the author (optional). +/// - `homepage` - the homepage of the project (optional). +/// - `keywords` - keywords that describe the project (optional). +/// - `license` - the license under which the project is released (optional). +/// - `name` - the name of the project (optional). +/// - `output` - the output directory where the project files will be created (required). +/// - `readme` - the name of the readme file (optional). +/// - `repository` - the url of the project's repository (optional). +/// - `rustversion` - the minimum Rust version required by the project (optional). +/// - `version` - the initial version of the project (optional). +/// - `website` - the website of the project (optional). +/// +/// # Errors +/// +/// This function will return an error in the following situations: +/// +/// - If the specified CSV file cannot be found, read, or is not valid CSV. +/// - If an error occurs while parsing the CSV data into the `FileGenerationParams` struct. +/// - If there is an error in generating files based on the parameters from each CSV record. +/// +pub fn generate_from_csv(path: &str) -> io::Result<()> { + let mut reader = Reader::from_path(path)?; + for result in reader.records() { + let record = result?; + let params = FileGenerationParams { + author: record.get(0).map(ToString::to_string), + build: record.get(1).map(ToString::to_string), + categories: record.get(2).map(ToString::to_string), + description: record.get(3).map(ToString::to_string), + documentation: record.get(4).map(ToString::to_string), + edition: record.get(5).map(ToString::to_string), + email: record.get(6).map(ToString::to_string), + homepage: record.get(7).map(ToString::to_string), + keywords: record.get(8).map(ToString::to_string), + license: record.get(9).map(ToString::to_string), + name: record.get(10).map(ToString::to_string), + output: record.get(11).map(ToString::to_string), + readme: record.get(12).map(ToString::to_string), + repository: record.get(13).map(ToString::to_string), + rustversion: record.get(14).map(ToString::to_string), + version: record.get(15).map(ToString::to_string), + website: record.get(16).map(ToString::to_string), + }; + macro_generate_files!(params.clone()) + .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; + } + Ok(()) +} diff --git a/src/generators/ini.rs b/src/generators/ini.rs new file mode 100644 index 0000000..9962912 --- /dev/null +++ b/src/generators/ini.rs @@ -0,0 +1,45 @@ +use std::fs; +use std::io; +use serde_ini::from_str; +use crate::models::model_params::FileGenerationParams; +use crate::macro_generate_files; + +/// Generates files for a new Rust project based on an INI file. +/// +/// The INI file must contain a single section with the following +/// keys: +/// - `author` - the author of the project (optional). +/// - `build` - the build command to be used for building the project (optional). +/// - `categories` - the categories that the project belongs to (optional). +/// - `description` - a short description of the project (optional). +/// - `documentation` - the documentation URL of the project (optional). +/// - `edition` - the edition of the project (optional). +/// - `email` - the email address of the author (optional). +/// - `homepage` - the homepage of the project (optional). +/// - `keywords` - keywords that describe the project (optional). +/// - `license` - the license under which the project is released (optional). +/// - `name` - the name of the project (optional). +/// - `output` - the output directory where the project files will be created (required). +/// - `readme` - the name of the readme file (optional). +/// - `repository` - the url of the project's repository (optional). +/// - `rustversion` - the minimum Rust version required by the project (optional). +/// - `version` - the initial version of the project (optional). +/// - `website` - the website of the project (optional). +/// +/// # Errors +/// +/// This function will return an error in the following situations: +/// +/// - If the specified INI file cannot be found, read, or is not valid UTF-8. +/// - If the INI data cannot be parsed into the `FileGenerationParams` struct. +/// - If there is an error in generating files based on the parameters. +/// +pub fn generate_from_ini(path: &str) -> io::Result<()> { + let contents = fs::read_to_string(path)?; + let params: FileGenerationParams = from_str(&contents) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e.to_string()))?; + macro_generate_files!(params.clone()).map_err(|e| { + io::Error::new(io::ErrorKind::Other, e) + })?; + Ok(()) +} diff --git a/src/generators/json.rs b/src/generators/json.rs new file mode 100644 index 0000000..d6c855a --- /dev/null +++ b/src/generators/json.rs @@ -0,0 +1,47 @@ +use std::fs; +use std::io; +use crate::models::model_params::FileGenerationParams; +use crate::macro_generate_files; + +/// Generates files for a new Rust project based on a JSON file. +/// +/// # Arguments +/// +/// The JSON file must contain a single object with the following +/// properties: +/// +/// - `author` - the author of the project (optional). +/// - `build` - the build command to be used for building the project (optional). +/// - `categories` - the categories that the project belongs to (optional). +/// - `description` - a short description of the project (optional). +/// - `documentation` - the documentation URL of the project (optional). +/// - `edition` - the edition of the project (optional). +/// - `email` - the email address of the author (optional). +/// - `homepage` - the homepage of the project (optional). +/// - `keywords` - keywords that describe the project (optional). +/// - `license` - the license under which the project is released (optional). +/// - `name` - the name of the project (optional). +/// - `output` - the output directory where the project files will be created (required). +/// - `readme` - the name of the readme file (optional). +/// - `repository` - the url of the project's repository (optional). +/// - `rustversion` - the minimum Rust version required by the project (optional). +/// - `version` - the initial version of the project (optional). +/// - `website` - the website of the project (optional). +/// +/// # Errors +/// +/// This function will return an error in the following situations: +/// +/// - If the specified JSON file cannot be found, read, or is not valid UTF-8. +/// - If the JSON data cannot be deserialized into the `FileGenerationParams` struct. +/// - If there is an error in generating files based on the parameters. +/// +pub fn generate_from_json(path: &str) -> io::Result<()> { + let contents = fs::read_to_string(path)?; + let params: FileGenerationParams = serde_json::from_str(&contents) + .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?; + macro_generate_files!(params.clone()).map_err(|e| { + io::Error::new(io::ErrorKind::Other, e) + })?; + Ok(()) +} diff --git a/src/generators/mod.rs b/src/generators/mod.rs new file mode 100644 index 0000000..488278a --- /dev/null +++ b/src/generators/mod.rs @@ -0,0 +1,26 @@ +// Copyright notice and licensing information. +// These lines indicate the copyright of the software and its licensing terms. +// SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. +// Copyright ยฉ 2024 LibMake. All rights reserved. + +/// The `ascii` module contains functionality for generating ASCII art from +/// text using the FIGlet library. +pub mod ascii; + +/// The `args` module contains functionality for parsing command-line arguments. +pub mod args; + +/// The `csv` module contains functionality for parsing CSV files. +pub mod csv; + +/// The `ini` module contains functionality for parsing INI files. +pub mod ini; + +/// The `json` module contains functionality for parsing JSON files. +pub mod json; + +/// The `toml` module contains functionality for parsing TOML files. +pub mod toml; + +/// The `yaml` module contains functionality for parsing YAML files. +pub mod yaml; diff --git a/src/generators/toml.rs b/src/generators/toml.rs new file mode 100644 index 0000000..41b36c7 --- /dev/null +++ b/src/generators/toml.rs @@ -0,0 +1,45 @@ +use std::fs; +use std::io; +use crate::models::model_params::FileGenerationParams; +use crate::macro_generate_files; + +/// Generates files for a new Rust project based on a TOML file. +/// +/// The TOML file must contain a single object with the following +/// properties: +/// +/// - `author` - the author of the project (optional). +/// - `build` - the build command to be used for building the project (optional). +/// - `categories` - the categories that the project belongs to (optional). +/// - `description` - a short description of the project (optional). +/// - `documentation` - the documentation URL of the project (optional). +/// - `edition` - the edition of the project (optional). +/// - `email` - the email address of the author (optional). +/// - `homepage` - the homepage of the project (optional). +/// - `keywords` - keywords that describe the project (optional). +/// - `license` - the license under which the project is released (optional). +/// - `name` - the name of the project (optional). +/// - `output` - the output directory where the project files will be created (required). +/// - `readme` - the name of the readme file (optional). +/// - `repository` - the url of the project's repository (optional). +/// - `rustversion` - the minimum Rust version required by the project (optional). +/// - version - the initial version of the project (optional). +/// - website - the website of the project (optional). +/// +/// # Errors +/// +/// This function will return an error in the following situations: +/// +/// - If the specified TOML file cannot be found, read, or is not valid UTF-8. +/// - If the TOML data cannot be deserialized into the FileGenerationParams struct. +/// - If there is an error in generating files based on the parameters. +/// +pub fn generate_from_toml(path: &str) -> io::Result<()> { + let contents = fs::read_to_string(path)?; + let params: FileGenerationParams = toml::from_str(&contents) + .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; + macro_generate_files!(params.clone()).map_err(|e| { + io::Error::new(io::ErrorKind::Other, e) + })?; + Ok(()) +} diff --git a/src/generators/yaml.rs b/src/generators/yaml.rs new file mode 100644 index 0000000..42ee3d0 --- /dev/null +++ b/src/generators/yaml.rs @@ -0,0 +1,45 @@ +use std::fs; +use std::io; +use crate::models::model_params::FileGenerationParams; +use crate::macro_generate_files; + +/// Generates files for a new Rust project based on a YAML file. +/// +/// The YAML file must contain a single object with the following +/// properties: +/// +/// - `author` - the author of the project (optional). +/// - `build` - the build command to be used for building the project (optional). +/// - `categories` - the categories that the project belongs to (optional). +/// - `description` - a short description of the project (optional). +/// - `documentation` - the documentation URL of the project (optional). +/// - `edition` - the edition of the project (optional). +/// - `email` - the email address of the author (optional). +/// - `homepage` - the homepage of the project (optional). +/// - `keywords` - keywords that describe the project (optional). +/// - `license` - the license under which the project is released (optional). +/// - `name` - the name of the project (optional). +/// - `output` - the output directory where the project files will be created (required). +/// - `readme` - the name of the readme file (optional). +/// - `repository` - the url of the project's repository (optional). +/// - `rustversion` - the minimum Rust version required by the project (optional). +/// - `version` - the initial version of the project (optional). +/// - `website` - the website of the project (optional). +/// +/// # Errors +/// +/// This function will return an error in the following situations: +/// +/// - If the specified YAML file cannot be found, read, or is not valid UTF-8. +/// - If the YAML data cannot be deserialized into the `FileGenerationParams` struct. +/// - If there is an error in generating files based on the parameters. +/// +pub fn generate_from_yaml(path: &str) -> io::Result<()> { + let contents = fs::read_to_string(path)?; + let params: FileGenerationParams = serde_yaml::from_str(&contents) + .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; + macro_generate_files!(params.clone()).map_err(|e| { + io::Error::new(io::ErrorKind::Other, e) + })?; + Ok(()) +} diff --git a/src/interface.rs b/src/interface.rs index 6bc43c9..a4ae0b2 100644 --- a/src/interface.rs +++ b/src/interface.rs @@ -8,8 +8,8 @@ use std::{ io::{BufRead, BufReader, Write}, path::PathBuf, }; - -use super::generator::FileGenerationParams; +use crate::models::model_params::FileGenerationParams; +use crate::macro_replace_placeholder; /// Replaces placeholders in a template file with values from the provided parameters /// and writes the result to an output file. @@ -37,70 +37,32 @@ pub fn replace_placeholders( let tpl_reader = BufReader::new(tpl); let mut output = File::create(output_file)?; let tpl_lines = tpl_reader.lines(); + for line in tpl_lines { let line = line?; - let replaced_line = line - .replace( - "{author}", - params.author.as_ref().unwrap_or(&String::new()), - ) - .replace( - "{build}", - params.build.as_ref().unwrap_or(&String::new()), - ) - .replace( - "{categories}", - params.categories.as_ref().unwrap_or(&String::new()), - ) - .replace( - "{description}", - params.description.as_ref().unwrap_or(&String::new()), - ) - .replace( - "{documentation}", - params.documentation.as_ref().unwrap_or(&String::new()), - ) - .replace( - "{edition}", - params.edition.as_ref().unwrap_or(&String::new()), - ) - .replace( - "{email}", - params.email.as_ref().unwrap_or(&String::new()), - ) - .replace( - "{homepage}", - params.homepage.as_ref().unwrap_or(&String::new()), - ) - .replace( - "{keywords}", - params.keywords.as_ref().unwrap_or(&String::new()), - ) - .replace( - "{license}", - params.license.as_ref().unwrap_or(&String::new()), - ) - .replace( - "{name}", - params.name.as_ref().unwrap_or(&String::new()), - ) - .replace( - "{repository}", - params.repository.as_ref().unwrap_or(&String::new()), - ) - .replace( - "{rustversion}", - params.rustversion.as_ref().unwrap_or(&String::new()), - ) - .replace( - "{version}", - params.version.as_ref().unwrap_or(&String::new()), - ) - .replace( - "{website}", - params.website.as_ref().unwrap_or(&String::new()), - ); + let replaced_line = macro_replace_placeholder!( + line, + params, + author, + build, + categories, + description, + documentation, + edition, + email, + homepage, + keywords, + license, + name, + output, + readme, + repository, + rustversion, + version, + website + ); writeln!(output, "{replaced_line}")?; } + Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 46db36f..723f727 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,7 @@ //! //! [![Rust](https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust)](https://www.rust-lang.org) //! [![Crates.io](https://img.shields.io/crates/v/libmake.svg?style=for-the-badge&color=success&labelColor=27A006)](https://crates.io/crates/libmake) -//! [![Lib.rs](https://img.shields.io/badge/lib.rs-v0.2.2-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://lib.rs/crates/libmake) +//! [![Lib.rs](https://img.shields.io/badge/lib.rs-v0.2.3-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://lib.rs/crates/libmake) //! [![GitHub](https://img.shields.io/badge/github-555555?style=for-the-badge&labelColor=000000&logo=github)](https://github.com/sebastienrousseau/libmake) //! [![License](https://img.shields.io/crates/l/libmake.svg?style=for-the-badge&color=007EC6&labelColor=03589B)](http://opensource.org/licenses/MIT) //! @@ -80,18 +80,17 @@ // Import necessary dependencies use crate::args::process_arguments; -use crate::ascii::generate_ascii_art; use crate::cli::build; use dtt::DateTime; use rlg::{log_format::LogFormat, log_level::LogLevel, macro_log}; use std::{error::Error, fs::File, io::Write}; -use uuid::Uuid; +use crate::utilities::uuid::generate_unique_string; /// The `args` module contains functions for processing command-line /// arguments. pub mod args; -/// The `ascii` module contains functions for generating ASCII art. -pub mod ascii; +/// The `generators` module contains functions for generating code. +pub mod generators; /// The `cli` module contains functions for processing command-line /// input. pub mod cli; @@ -103,10 +102,15 @@ pub mod generator; pub mod interface; /// The `macros` module contains functions for generating macros. pub mod macros; +/// The `models` module contains the models for the library. +pub mod models; /// The `utils` module contains a function for reading a CSV file at the /// given file path and returns the value of the given field. pub mod utils; +/// The `utilities` module contains utility functions for the library. +pub mod utilities; + /// Initializes the logger with a file logger and a terminal logger and processes /// command-line arguments to generate the new library. /// @@ -121,14 +125,13 @@ pub mod utils; pub fn run() -> Result<(), Box> { let date = DateTime::new(); let iso = date.iso_8601; - let uuid = Uuid::new_v4().to_string(); // Open the log file for appending let mut log_file = File::create("./libmake.log")?; // Generate ASCII art for the tool's CLI let log = macro_log!( - &uuid, + &generate_unique_string(), &iso, &LogLevel::INFO, "deps", @@ -138,12 +141,11 @@ pub fn run() -> Result<(), Box> { // Write the log to both the console and the file writeln!(log_file, "{}", log)?; - match generate_ascii_art("LibMake") { - Ok(ascii_art) => println!("{}", ascii_art), - Err(e) => eprintln!("Error generating ASCII art: {:?}", e), - } + // Printing the ASCII art to the console + println!("{}", macro_ascii!("LibMake")); + let log = macro_log!( - &uuid, + &generate_unique_string(), &iso, &LogLevel::INFO, "deps", @@ -159,7 +161,7 @@ pub fn run() -> Result<(), Box> { // Check the number of arguments, provide a welcome message if no arguments were passed macro_log!( - &uuid, + &generate_unique_string(), &iso, &LogLevel::INFO, "cli", diff --git a/src/macros.rs b/src/macros.rs deleted file mode 100644 index 4bb0a47..0000000 --- a/src/macros.rs +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright notice and licensing information. -// These lines indicate the copyright of the software and its licensing terms. -// SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. -// Copyright ยฉ 2024 LibMake. All rights reserved. - -//! Macros for the `libmake` crate. -//! -//! This module provides macros for asserting the creation of directories, -//! generating templates from JSON, YAML, and CSV files, and custom logging functionality. - -// Macro for creating a new directory at the specified path. -#[macro_export] -/// Asserts that a directory is created at the given path. -/// -/// # Arguments -/// -/// * `$path` - A string literal specifying the path where the directory will be created. -/// -/// # Panics -/// -/// Panics if the directory cannot be created. -macro_rules! assert_create_directory { - ($path:expr) => { - use std::fs::{self, create_dir_all}; - use std::path::Path; - assert!( - create_dir_all(Path::new($path)).is_ok(), - "Failed to create directory at: {}", - $path - ); - }; -} - -// Macro for generating file templates using a command-line interface. -#[macro_export] -/// Asserts that file templates are generated from the given parameters. -/// -/// # Arguments -/// -/// * `$params` - Parameters for file generation. -/// -/// # Panics -/// -/// Panics if the files cannot be generated. -macro_rules! assert_generate_files { - ($params:expr) => { - assert!( - generate_files($params).is_ok(), - "Failed to generate files with parameters: {:?}", - $params - ); - }; -} - -// Macro for generating file templates from a CSV file. -#[macro_export] -/// Asserts that file templates are generated from a CSV file. -/// -/// # Arguments -/// -/// * `$csv_path` - The path to the CSV file. -/// -/// # Panics -/// -/// Panics if the files cannot be generated from the CSV. -macro_rules! assert_generate_from_csv { - ($csv_path:expr) => { - assert!( - generate_from_csv($csv_path).is_ok(), - "Failed to generate files from CSV at: {}", - $csv_path - ); - }; -} - -// Macro for generating file templates from a JSON file. -#[macro_export] -/// Asserts that file templates are generated from a JSON file. -/// -/// # Arguments -/// -/// * `$json_path` - The path to the JSON file. -/// -/// # Panics -/// -/// Panics if the files cannot be generated from the JSON. -macro_rules! assert_generate_from_json { - ($json_path:expr) => { - assert!( - generate_from_json($json_path).is_ok(), - "Failed to generate files from JSON at: {}", - $json_path - ); - }; -} - -// Macro for generating file templates from a YAML file. -#[macro_export] -/// Asserts that file templates are generated from a YAML file. -/// -/// # Arguments -/// -/// * `$yaml_path` - The path to the YAML file. -/// -/// # Panics -/// -/// Panics if the files cannot be generated from the YAML. -macro_rules! assert_generate_from_yaml { - ($yaml_path:expr) => { - assert!( - generate_from_yaml($yaml_path).is_ok(), - "Failed to generate files from YAML at: {}", - $yaml_path - ); - }; -} - -// Macro for generating file templates from a configuration file. -#[macro_export] -/// Asserts that file templates are generated from a configuration file. -/// -/// # Arguments -/// -/// * `$path` - The path to the configuration file. -/// * `$file_type` - The type of the configuration file: `json`, `yaml` or `csv`. -/// -/// # Panics -/// -/// Panics if the files cannot be generated from the configuration file. -macro_rules! assert_generate_from_config { - ($path:expr, $file_type:expr) => { - assert!( - generate_from_config($path, $file_type).is_ok(), - "Failed to generate files from {} configuration at: {}", - $file_type, - $path - ); - }; -} -// Macro for logging information with various log levels and formats. -#[macro_export] -/// Logs information with the specified level, component, and format. -/// -/// # Parameters -/// -/// * `$level` - The log level for the message. -/// * `$component` - The component where the log message originates. -/// * `$description` - A description for the log message. -/// * `$format` - The format for the log message. -/// -/// # Returns -/// -/// This macro returns the created `Log` instance. -macro_rules! macro_log_info { - ($level:expr, $component:expr, $description:expr, $format:expr) => {{ - use dtt::DateTime; - use vrd::Random; - use $crate::loggers::{Log, LogFormat, LogLevel}; - - // Get the current date and time in ISO 8601 format. - let date = DateTime::new(); - let iso = date.iso_8601; - - // Create a new random number generator - let mut rng = Random::default(); - let session_id = rng.rand().to_string(); - - let log = Log::new( - &session_id, - &iso, - $level, - $component, - $description, - $format, - ); - let _ = log.log(); - log // Return the Log instance - }}; -} -// Macro for executing a shell command and logging the operation. -#[macro_export] -/// Executes a shell command and logs the start, completion, and any errors. -/// -/// # Parameters -/// -/// * `$command` - The shell command to execute. -/// * `$package` - The name of the package being operated on. -/// * `$operation` - A description of the operation. -/// * `$start_message` - The message to log at the start of the operation. -/// * `$complete_message` - The message to log upon successful completion. -/// * `$error_message` - The message to log in case of an error. -/// -/// # Returns -/// -/// Returns a `Result<(), anyhow::Error>` to indicate the success or failure of the command execution. -macro_rules! macro_execute_and_log { - ($command:expr, $package:expr, $operation:expr, $start_message:expr, $complete_message:expr, $error_message:expr) => {{ - use anyhow::{Context, Result as AnyResult}; - use $crate::loggers::{LogFormat, LogLevel}; - use $crate::macro_log_info; - - macro_log_info!( - LogLevel::INFO, - $operation, - $start_message, - LogFormat::CLF - ); - - $command - .run() - .map(|_| ()) - .map_err(|err| { - macro_log_info!( - LogLevel::ERROR, - $operation, - $error_message, - LogFormat::CLF - ); - err - }) - .with_context(|| { - format!( - "Failed to execute '{}' for {} on package '{}'", - stringify!($command), - $operation, - $package - ) - })?; - - macro_log_info!( - LogLevel::INFO, - $operation, - $complete_message, - LogFormat::CLF - ); - Ok(()) - }}; -} - -/// Extracts a parameter from a `Matches` object. -/// -/// This macro takes two arguments: `$matches` and `$name`. It attempts to retrieve the value -/// associated with `$name` from the `$matches` object. If the value is found and is of type `String`, -/// it returns a `Some` variant containing a cloned copy of the value. Otherwise, it returns `None`. -/// -/// # Arguments -/// -/// * `$matches` - A `Matches` object that contains the parameter values. -/// * `$name` - The name of the parameter to extract. -/// -/// # Returns -/// -/// A `Option` containing the extracted parameter value, or `None` if the parameter is not found -/// or is not of type `String`. -#[macro_export] -macro_rules! extract_param { - ($matches:expr, $name:expr) => { - $matches.get_one::($name).map(|s| s.to_owned()) - }; -} diff --git a/src/macros/ascii_macros.rs b/src/macros/ascii_macros.rs new file mode 100644 index 0000000..7d2a514 --- /dev/null +++ b/src/macros/ascii_macros.rs @@ -0,0 +1,28 @@ +// Copyright notice and licensing information. +// These lines indicate the copyright of the software and its licensing terms. +// SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. +// Copyright ยฉ 2024 LibMake. All rights reserved. + +/// A macro for generating ASCII art from text. +/// +/// This macro takes a string literal as input and generates ASCII art using the `generate_ascii_art` function. +/// If the conversion is successful, the macro returns the ASCII art as a string. +/// If an error occurs during the conversion, the macro panics with an error message. +/// +/// # Examples +/// +/// ``` +/// use libmake::macro_ascii; +/// +/// let art = macro_ascii!("Hello, world!"); +/// println!("{}", art); +/// ``` +#[macro_export] +macro_rules! macro_ascii { + ($text:expr) => { + match $crate::generators::ascii::generate_ascii_art($text) { + Ok(art) => art, + Err(err) => panic!("Failed to generate ASCII art: {}", err), + } + }; +} diff --git a/src/macros/directory_macros.rs b/src/macros/directory_macros.rs new file mode 100644 index 0000000..978e89b --- /dev/null +++ b/src/macros/directory_macros.rs @@ -0,0 +1,266 @@ +// Copyright notice and licensing information. +// These lines indicate the copyright of the software and its licensing terms. +// SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. +// Copyright ยฉ 2024 LibMake. All rights reserved. + +//! This module provides macros for directory operations, including checking directory existence, +//! creating multiple directories at once, and cleaning up directories. +//! +//! # `macro_check_directory` Macro +//! +//! Checks if a directory exists and creates it if necessary. +//! +//! ## Usage +//! +//! ```rust +//! use libmake::macro_check_directory; +//! use std::path::Path; +//! +//! let path = Path::new("logs"); +//! macro_check_directory!(path, "logs"); +//! ``` +//! +//! ## Arguments +//! +//! * `_dir` - The path to check, as a `std::path::Path`. +//! * `_name` - A string literal representing the directory name. This is used in error messages. +//! +//! ## Behaviour +//! +//! The `macro_check_directory` macro checks if the directory specified by `_dir` exists. +//! If it exists and is not a directory, a panic with an error message is triggered. +//! If the directory doesn't exist, the macro attempts to create it using `std::fs::create_dir_all(_dir)`. +//! +//! # `macro_cleanup_directories` Macro +//! +//! Cleans up multiple directories by invoking the `cleanup_directory` function. +//! +//! ## Usage +//! +//! ```rust +//! use std::path::Path; +//! use libmake::macro_check_directory; +//! +//! let path = Path::new("logs"); +//! macro_check_directory!(path, "logs"); +//! ``` +//! +//! ## Arguments +//! +//! * `$( $_dir:expr ),*` - A comma-separated list of directory paths to clean up. +//! +//! ## Behaviour +//! +//! The `macro_cleanup_directories` macro takes multiple directory paths as arguments +//! and invokes the `cleanup_directory` function for each path. +//! +//! # `macro_create_directories` Macro +//! +//! Creates multiple directories at once. +//! +//! ## Usage +//! +//! ```rust +//! use libmake::{macro_create_directories, macro_cleanup_directories}; +//! use std::path::Path; +//! +//! macro_create_directories!("logs", "logs1", "logs2"); +//! macro_cleanup_directories!(Path::new("./logs"), Path::new("./logs1"), Path::new("./logs2")); +//! ``` +//! +//! ## Arguments +//! +//! * `...` - Variable number of directory paths, each specified as an expression (`expr`). +//! +//! ## Behaviour +//! +//! The `macro_create_directories` macro creates multiple directories at once. +//! +//! ## Example +//! +//! ```rust +//! use libmake::{macro_create_directories, macro_cleanup_directories}; +//! use std::path::Path; +//! +//! fn main() -> Result<(), Box> { +//! let test = Path::new("logs"); +//! let test2 = Path::new("logs1"); +//! macro_create_directories!(test, test2)?; +//! macro_cleanup_directories!(test, test2); +//! Ok(()) +//! } +//! ``` +//! +//! # Note +//! +//! These macros assume familiarity with Rust macros and their usage. +//! Users are encouraged to review Rust macro documentation for a better understanding +//! of how to work with macros effectively. + +/// # `macro_check_directory` Macro +/// +/// Check if a directory exists and create it if necessary. +/// +/// ## Usage +/// +/// ```rust +/// use libmake::macro_check_directory; +/// use std::path::Path; +/// +/// let path = Path::new("logs"); +/// macro_check_directory!(path, "logs"); +/// ``` +/// +/// ## Arguments +/// +/// * `_dir` - The path to check, as a `std::path::Path`. +/// * `_name` - A string literal representing the directory name. This is used in error messages. +/// +/// ## Behaviour +/// +/// The `macro_check_directory` macro checks if the directory specified by `_dir` exists. If it exists and is not a directory, a panic with an error message is triggered. If the directory doesn't exist, the macro attempts to create it using `std::fs::create_dir_all(_dir)`. If the creation is successful, no action is taken. If an error occurs during the directory creation, a panic is triggered with an error message indicating the failure. +/// +/// Please note that the macro panics on failure. Consider using this macro in scenarios where panicking is an acceptable behaviour, such as during application startup or setup. +/// +/// # See Also +/// +/// - [`macro_create_directories`] for creating multiple directories +/// - [`macro_cleanup_directories`] for cleaning up directories +/// +#[macro_export] +macro_rules! macro_check_directory { + ($_dir:expr, $_name:expr) => {{ + let directory: &std::path::Path = $_dir; + let name = $_name; + if directory.exists() { + if !directory.is_dir() { + log::warn!("โŒ '{}' is not a directory.", name); + panic!("โŒ '{}' is not a directory.", name); + } + } else { + match std::fs::create_dir_all(directory) { + Ok(_) => {} + Err(e) => { + log::error!( + "โŒ Cannot create '{}' directory: {}", + name, + e + ); + panic!( + "โŒ Cannot create '{}' directory: {}", + name, e + ) + } + } + } + }}; +} + +/// # `macro_cleanup_directories` Macro +/// +/// Cleanup multiple directories by invoking the `cleanup_directory` function. +/// +/// ## Usage +/// +/// ```rust +/// use std::path::Path; +/// use libmake::macro_check_directory; +/// +/// let path = Path::new("logs"); +/// macro_check_directory!(path, "logs"); +/// ``` +/// +/// ## Arguments +/// +/// * `$( $_dir:expr ),*` - A comma-separated list of directory paths to clean up. +/// +/// ## Behaviour +/// +/// The `macro_cleanup_directories` macro takes multiple directory paths as arguments and invokes the `cleanup_directory` function for each path. It is assumed that the `cleanup_directory` function is available in the crate's utilities module (`$crate::utilities::cleanup_directory`). +/// +/// The macro creates an array `directories` containing the provided directory paths and passes it as an argument to `cleanup_directory`. The `cleanup_directory` function is responsible for performing the cleanup operations. +/// +/// Please note that the macro uses the `?` operator for error propagation. It expects the `cleanup_directory` function to return a `Result` type. If an error occurs during the cleanup process, it will be propagated up the call stack, allowing the caller to handle it appropriately. +/// +/// # See Also +/// +/// - [`macro_check_directory`] for checking and creating a single directory +/// - [`macro_create_directories`] for creating multiple directories +/// +#[macro_export] +macro_rules! macro_cleanup_directories { + ( $( $_dir:expr ),* ) => { + { + use $crate::utilities::directory::cleanup_directory; + let directories: &[&Path] = &[ $( $_dir ),* ]; + match cleanup_directory(directories) { + Ok(()) => (), + Err(err) => { + log::error!("Cleanup failed: {:?}", err); + panic!("Cleanup failed: {:?}", err); + }, + } + } + }; +} + +/// # `macro_create_directories` Macro +/// +/// Create multiple directories at once. +/// +/// ## Usage +/// +/// ```rust +/// use libmake::{macro_create_directories, macro_cleanup_directories}; +/// use std::path::Path; +/// macro_create_directories!("logs", "logs1", "logs2"); +/// macro_cleanup_directories!(Path::new("./logs"), Path::new("./logs1"), Path::new("./logs2")); +/// ``` +/// +/// ## Arguments +/// +/// * `...` - Variable number of directory paths, each specified as an expression (`expr`). +/// +/// ## Behaviour +/// +/// The `macro_create_directories` macro creates multiple directories at once. It takes a variable number of directory paths as arguments and uses the `create_directory` utility function from the `$crate` crate to create the directories. +/// +/// The directories are specified as expressions and separated by commas. For example, `macro_create_directories!("logs", "logs1", "logs2")` will attempt to create the `logs`, `logs1`, and `logs2`. +/// +/// The macro internally creates a slice of the directory paths and passes it to the `create_directory` function. If any error occurs during the directory creation, the macro returns an `Err` value, indicating the first encountered error. Otherwise, it returns `Ok(())`. +/// +/// ## Example +/// +/// ```rust +/// use libmake::{macro_create_directories, macro_cleanup_directories}; +/// use std::path::Path; +/// +/// fn main() -> Result<(), Box> { +/// let test = Path::new("logs"); +/// let test2 = Path::new("logs1"); +/// macro_create_directories!(test, test2)?; +/// macro_cleanup_directories!(test, test2); +/// Ok(()) +/// } +/// ``` +/// +/// # See Also +/// +/// - [`macro_check_directory`] for checking and creating a single directory +/// - [`macro_cleanup_directories`] for cleaning up directories +/// +#[macro_export] +macro_rules! macro_create_directories { + ( $( $_dir:expr ),* ) => {{ + use $crate::utilities::directory::create_directory; + use std::path::Path; + let directories: Vec<&Path> = vec![ $( Path::new($_dir) ),* ]; + match create_directory(&directories) { + Ok(_) => Ok(()), + Err(err) => { + log::error!("Directory creation failed: {:?}", err); + Err(err) + }, + } + }}; +} diff --git a/src/macros/file_macros.rs b/src/macros/file_macros.rs new file mode 100644 index 0000000..346d11c --- /dev/null +++ b/src/macros/file_macros.rs @@ -0,0 +1,17 @@ +// Copyright notice and licensing information. +// These lines indicate the copyright of the software and its licensing terms. +// SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. +// Copyright ยฉ 2024 LibMake. All rights reserved. + +/// Macro to simplify the match logic for file generation. +#[macro_export] +macro_rules! generate_file { + ($file_type:expr, $value:expr, $generator:expr) => { + if !$value.trim().is_empty() { + if let Err(err) = $generator($value) { + eprintln!("Error generating {} file: {}", $file_type, err); + } + } + }; +} + diff --git a/src/macros/generator_macros.rs b/src/macros/generator_macros.rs new file mode 100644 index 0000000..c519fa5 --- /dev/null +++ b/src/macros/generator_macros.rs @@ -0,0 +1,250 @@ +// Copyright notice and licensing information. +// These lines indicate the copyright of the software and its licensing terms. +// SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. +// Copyright ยฉ 2024 LibMake. All rights reserved. + +//! Macros for the `libmake` crate. +//! +//! This module provides macros for generating templates from various configuration files +//! (JSON, YAML, CSV, INI, TOML), and for executing operations with logging. +//! +//! Each macro is documented with its purpose and usage, ensuring clear and maintainable code. +//! For detailed examples and error handling strategies, refer to the crate's documentation. + +// Macro for generating file templates using a command-line interface. +#[macro_export] +/// Attempts to generate file templates from the given parameters. +/// +/// # Arguments +/// +/// * `$params` - Parameters for file generation, specified as `FileGenerationParams`. +/// +/// # Returns +/// +/// Returns a `Result<(), String>` indicating the success or failure of file generation. +/// If successful, returns `Ok(())`. If an error occurs, returns `Err` with an error message. +macro_rules! macro_generate_files { + ($params:expr) => {{ + use $crate::generator::generate_files; + match generate_files($params) { + Ok(_) => Ok(()), + Err(e) => Err(format!("Failed to generate files with parameters: {:?} - Error: {}", $params, e)), + } + }}; +} + +#[macro_export] +/// Attempts to generate file templates from a CSV file. +/// +/// # Arguments +/// +/// * `$csv_path` - The path to the CSV file as a string slice. +/// +/// # Returns +/// +/// Returns a `Result<(), String>` indicating the success or failure of file generation. +/// If successful, returns `Ok(())`. If an error occurs, returns `Err` with an error message. +macro_rules! macro_generate_from_csv { + ($csv_path:expr) => {{ + use $crate::generators::csv::generate_from_csv; + match generate_from_csv($csv_path) { + Ok(_) => Ok(()), + Err(e) => Err(format!("Failed to generate files from CSV at: {} - Error: {}", $csv_path, e)), + } + }}; +} + +#[macro_export] +/// Attempts to generate file templates from a INI file. +/// +/// # Arguments +/// +/// * `$ini_path` - The path to the INI file as a string slice. +/// +/// # Returns +/// +/// Returns a `Result<(), String>` indicating the success or failure of file generation. +/// If successful, returns `Ok(())`. If an error occurs, returns `Err` with an error message. +macro_rules! macro_generate_from_ini { + ($ini_path:expr) => {{ + use $crate::generators::ini::generate_from_ini; + match generate_from_ini($ini_path) { + Ok(_) => Ok(()), + Err(e) => Err(format!("Failed to generate files from INI at: {} - Error: {}", $ini_path, e)), + } + }}; +} + +#[macro_export] +/// Attempts to generate file templates from a JSON file. +/// +/// # Arguments +/// +/// * `$json_path` - The path to the JSON file as a string slice. +/// +/// # Returns +/// +/// Returns a `Result<(), String>` indicating the success or failure of file generation. +/// If successful, returns `Ok(())`. If an error occurs, returns `Err` with an error message. +macro_rules! macro_generate_from_json { + ($json_path:expr) => {{ + use $crate::generators::json::generate_from_json; + match generate_from_json($json_path) { + Ok(_) => Ok(()), + Err(e) => Err(format!("Failed to generate files from JSON at: {} - Error: {}", $json_path, e)), + } + }}; +} + +#[macro_export] +/// Attempts to generate file templates from a TOML file. +/// +/// # Arguments +/// +/// * `$toml_path` - The path to the TOML file as a string slice. +/// +/// # Returns +/// +/// Returns a `Result<(), String>` indicating the success or failure of file generation. +/// If successful, returns `Ok(())`. If an error occurs, returns `Err` with an error message. +macro_rules! macro_generate_from_toml { + ($toml_path:expr) => {{ + use $crate::generators::toml::generate_from_toml; + match generate_from_toml($toml_path) { + Ok(_) => Ok(()), + Err(e) => Err(format!("Failed to generate files from TOML at: {} - Error: {}", $toml_path, e)), + } + }}; +} + +#[macro_export] +/// Attempts to generate file templates from a YAML file. +/// +/// # Arguments +/// +/// * `$yaml_path` - The path to the YAML file as a string slice. +/// +/// # Returns +/// +/// Returns a `Result<(), String>` indicating the success or failure of file generation. +/// If successful, returns `Ok(())`. If an error occurs, returns `Err` with an error message. +macro_rules! macro_generate_from_yaml { + ($yaml_path:expr) => {{ + use $crate::generators::yaml::generate_from_yaml; + match generate_from_yaml($yaml_path) { + Ok(_) => Ok(()), + Err(e) => Err(format!("Failed to generate files from YAML at: {} - Error: {}", $yaml_path, e)), + } + }}; +} + +#[macro_export] +/// Attempts to generate file templates from command-line arguments. +/// +/// # Arguments +/// +/// * `$args` - Command-line arguments as a string slice. +/// +/// # Returns +/// +/// Returns a `Result<(), String>` indicating the success or failure of file generation. +/// If successful, returns `Ok(())`. If an error occurs, returns `Err` with an error message. +macro_rules! macro_generate_from_args { + ($args:expr) => {{ + use $crate::generators::args::generate_from_args; + match generate_from_args($args) { + Ok(_) => Ok(()), + Err(e) => Err(format!("Failed to generate files from arguments: {:?} - Error: {}", $args, e)), + } + }}; +} + +#[macro_export] +/// Attempts to generate file templates from a configuration file. +/// +/// # Arguments +/// +/// * `$path` - The path to the configuration file as a string slice. +/// * `$file_type` - The type of the configuration file (e.g., "json", "yaml"). +/// +/// # Returns +/// +/// Returns a `Result<(), String>` indicating the success or failure of file generation. +/// If successful, returns `Ok(())`. If an error occurs, returns `Err` with an error message. +macro_rules! macro_generate_from_config { + ($path:expr, $file_type:expr) => {{ + use $crate::generator::generate_from_config; + match generate_from_config($path, $file_type) { + Ok(_) => Ok(()), + Err(e) => Err(format!("Failed to generate files from {} configuration at: {} - Error: {}", $file_type, $path, e)), + } + }}; +} + +#[macro_export] +/// Executes a shell command and logs the start, completion, and any errors. +/// +/// # Parameters +/// +/// * `$command` - The shell command to execute as a string slice. +/// * `$package` - The name of the package being operated on as a string slice. +/// * `$operation` - A description of the operation as a string slice. +/// * `$start_message` - The message to log at the start of the operation as a string slice. +/// * `$complete_message` - The message to log upon successful completion as a string slice. +/// * `$error_message` - The message to log in case of an error as a string slice. +/// +/// # Returns +/// +/// Returns a `Result<(), anyhow::Error>` to indicate the success or failure of the command execution. +macro_rules! macro_execute_and_log { + ($command:expr, $package:expr, $operation:expr, $start_message:expr, $complete_message:expr, $error_message:expr) => {{ + use anyhow::{Context, Result as AnyResult}; + // Using a fictional logging framework for demonstration purposes. You'll need to replace + // crate::log with your actual logging implementation. + $crate::log::info!("Starting operation: {}", $start_message); + + std::process::Command::new("sh") + .arg("-c") + .arg($command) + .output() + .map(|output| { + if output.status.success() { + $crate::log::info!("Operation completed successfully: {}", $complete_message); + Ok(()) + } else { + $crate::log::error!("Operation failed: {} - Error: {}", $error_message, String::from_utf8_lossy(&output.stderr)); + Err(std::io::Error::new(std::io::ErrorKind::Other, "Command execution failed").into()) + } + }) + .with_context(|| { + format!( + "Failed to execute '{}' for {} on package '{}'", + stringify!($command), + $operation, + $package + ) + }) + }}; +} + +/// Extracts a parameter from a `Matches` object. +/// +/// This macro takes two arguments: `$matches` and `$name`. It attempts to retrieve the value +/// associated with `$name` from the `$matches` object. If the value is found and is of type `String`, +/// it returns a `Some` variant containing a cloned copy of the value. Otherwise, it returns `None`. +/// +/// # Arguments +/// +/// * `$matches` - A `Matches` object that contains the parameter values. +/// * `$name` - The name of the parameter to extract. +/// +/// # Returns +/// +/// A `Option` containing the extracted parameter value, or `None` if the parameter is not found +/// or is not of type `String`. +#[macro_export] +macro_rules! extract_param { + ($matches:expr, $name:expr) => { + $matches.get_one::($name).map(|s| s.to_owned()) + }; +} diff --git a/src/macros/log_macros.rs b/src/macros/log_macros.rs new file mode 100644 index 0000000..8d89757 --- /dev/null +++ b/src/macros/log_macros.rs @@ -0,0 +1,56 @@ +// Copyright notice and licensing information. +// These lines indicate the copyright of the software and its licensing terms. +// SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. +// Copyright ยฉ 2024 LibMake. All rights reserved. + +//! This module contains macros related to logging messages at various log levels and formats. +//! +//! It includes a custom logging macro, `macro_log_info`, which allows logging messages with +//! specified log levels, components, descriptions, and formats. +//! +//! # Custom Logging Macro +//! +//! The `macro_log_info` macro is designed for logging messages with customizable log levels, +//! components, descriptions, and formats. It provides flexibility in defining log messages +//! according to specific requirements. +//! +//! # Parameters +//! +//! - `$level`: The log level of the message. +//! - `$component`: The component where the log is coming from. +//! - `$description`: A description of the log message. +//! - `$format`: The format of the log message. +//! + +/// Custom logging macro for various log levels and formats. +/// +/// # Parameters +/// +/// * `$level`: The log level of the message. +/// * `$component`: The component where the log is coming from. +/// * `$description`: A description of the log message. +/// * `$format`: The format of the log message. +/// +#[macro_export] +macro_rules! macro_log_info { + ($level:expr, $component:expr, $description:expr, $format:expr) => {{ + // Get the current date and time in ISO 8601 format. + let date = DateTime::new(); // Create a new DateTime instance + let iso = date.iso_8601; // Get ISO 8601 formatted date and time + + // Create a new random number generator + let mut rng = Random::default(); // Default random number generator + let session_id = rng.rand().to_string(); // Generate session ID + + // Create a new log instance + let log = Log::new( + &session_id, // Session ID + &iso, // ISO 8601 formatted date and time + $level, // Log level + $component, // Component name + $description, // Log description + $format, // Log format + ); + log // Return the Log instance + }}; +} diff --git a/src/macros/mod.rs b/src/macros/mod.rs new file mode 100644 index 0000000..9b82164 --- /dev/null +++ b/src/macros/mod.rs @@ -0,0 +1,20 @@ +/// A macro for generating ASCII art from text. +pub mod ascii_macros; + +/// The `directory_macros` module contains macros related to directory +/// operations. +pub mod directory_macros; + +/// The `file_macros` module contains macros related to file operations. +pub mod file_macros; + +/// The `generator_macros` module contains macros related to generating +/// templates from JSON, YAML, and CSV files, and custom logging functionality. +pub mod generator_macros; + +/// The `log_macros` module contains macros related to logging messages at various log levels and formats. +pub mod log_macros; + +/// The `utility_macros` module contains utility macros for common tasks such as +/// replacing placeholders in a line with values from parameters. +pub mod utility_macros; diff --git a/src/macros/utility_macros.rs b/src/macros/utility_macros.rs new file mode 100644 index 0000000..0f3c18e --- /dev/null +++ b/src/macros/utility_macros.rs @@ -0,0 +1,75 @@ +// Copyright notice and licensing information. +// These lines indicate the copyright of the software and its licensing terms. +// SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. +// Copyright ยฉ 2024 LibMake. All rights reserved. + +/// Replaces placeholders in a given line with corresponding values from the provided parameters. +/// +/// # Arguments +/// +/// * `line` - The line containing placeholders to be replaced. +/// * `params` - The parameters containing values to replace the placeholders. +/// * `$($field:ident),+` - Identifiers representing the fields in `params` to be replaced. +/// +/// # Returns +/// +/// The line with placeholders replaced by their corresponding values. +/// +#[macro_export] +macro_rules! macro_replace_placeholder { + ($line:expr, $params:expr, $($field:ident),+) => { + { + let mut line = $line; + $( + line = line.replace( + concat!("{", stringify!($field), "}"), + &$params.$field.as_deref().unwrap_or(""), + ); + )+ + line + } + }; +} + +/// Macro to generate a function that retrieves a field value from a JSON file. +/// +/// # Arguments +/// +/// * `$func_name` - The name of the generated function. +/// * `$deserializer` - The deserializer used to parse the JSON file. +/// +/// # Returns +/// +/// The generated function returns a `Result` containing the field value as a `String`, +/// or a `Box` if an error occurs. +/// +#[macro_export] +macro_rules! macro_get_field { + ($func_name:ident, $deserializer:expr) => { + /// Reads a file and deserializes its content using the specified + /// deserializer function. + pub fn $func_name( + // The path of the JSON file to read. + file_path: Option<&str>, + // The name of the field to retrieve. + field_name: &str, + ) -> Result> { + file_path.map_or_else( + || Ok(String::new()), + |file_path| { + let current_dir = env::current_dir()?; + let file_path = Path::new(¤t_dir).join(file_path); + read_file(&file_path, |file| { + let value: serde_json::Value = $deserializer(file)?; + let field_value = value.get(field_name) + .ok_or_else(|| format!("Field '{}' not found", field_name))? + .as_str() + .map(|s| s.to_string()) + .unwrap_or_else(|| value[field_name].to_string()); + Ok(field_value) + }) + }, + ) + } + }; +} diff --git a/src/models/error_ascii_art.rs b/src/models/error_ascii_art.rs new file mode 100644 index 0000000..ed37d5c --- /dev/null +++ b/src/models/error_ascii_art.rs @@ -0,0 +1,31 @@ +// Copyright notice and licensing information. +// These lines indicate the copyright of the software and its licensing terms. +// SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. +// Copyright ยฉ 2024 LibMake. All rights reserved. + +use std::error::Error; +use std::fmt; + +/// Error type for ASCII art generation failures. +#[derive(Debug)] +pub enum AsciiArtError { + /// Represents a failure to load the FIGfont. + FontLoadError, + /// Represents a failure to convert text to ASCII art. + ConversionError, +} + +impl fmt::Display for AsciiArtError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Self::FontLoadError => write!(f, "Failed to load FIGfont"), + Self::ConversionError => write!(f, "Failed to convert text to ASCII art"), + } + } +} + +impl Error for AsciiArtError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + None + } +} diff --git a/src/models/mod.rs b/src/models/mod.rs new file mode 100644 index 0000000..72e6ab4 --- /dev/null +++ b/src/models/mod.rs @@ -0,0 +1,10 @@ +// Copyright notice and licensing information. +// These lines indicate the copyright of the software and its licensing terms. +// SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. +// Copyright ยฉ 2024 LibMake. All rights reserved. + +/// The `ascii_art_error` module contains the `AsciiArtError` type for ASCII art generation failures. +pub mod error_ascii_art; + +/// The `model_params` module contains the `FileGenerationParams` type for holding the parameters for generating the project files. +pub mod model_params; diff --git a/src/models/model_params.rs b/src/models/model_params.rs new file mode 100644 index 0000000..3afa047 --- /dev/null +++ b/src/models/model_params.rs @@ -0,0 +1,192 @@ +// Copyright notice and licensing information. +// These lines indicate the copyright of the software and its licensing terms. +// SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. +// Copyright ยฉ 2024 LibMake. All rights reserved. + +use serde::{Deserialize, Serialize}; + +fn deserialize_name<'de, D>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let name = String::deserialize(deserializer)?; + Ok(Some(name.trim_matches('"').to_string())) +} + + +/// Structure for holding the parameters for generating the project files. +/// +/// # Description +/// +/// * The `output` directory is the directory where the project files will be created. +/// * The other parameters are optional and will be used to replace the placeholders in the template files. +/// * The template files are located in the template directory of the project. +/// * The template files are copied to the output directory and the placeholders are replaced with the values of the parameters. +/// +#[derive( + Clone, + Debug, + Default, + Deserialize, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, + Serialize, +)] +pub struct FileGenerationParams { + /// The author of the project (optional). + pub author: Option, + /// The build command to be used for building the project (optional). + pub build: Option, + /// The categories that the project belongs to (optional). + pub categories: Option, + /// A short description of the project (optional). + pub description: Option, + /// The documentation URL of the project (optional). + pub documentation: Option, + /// The edition of the project (optional). + pub edition: Option, + /// The email address of the author (optional). + pub email: Option, + /// The homepage of the project (optional). + pub homepage: Option, + /// Keywords that describe the project (optional). + pub keywords: Option, + /// The license under which the project is released (optional). + pub license: Option, + #[serde(deserialize_with = "deserialize_name")] + /// The name of the project (optional). + pub name: Option, + /// The output directory where the project files will be created (optional). + pub output: Option, + /// The name of the readme file (optional). + pub readme: Option, + #[serde(deserialize_with = "deserialize_name")] + /// The URL of the project's repository (optional). + pub repository: Option, + /// The minimum Rust version required by the project (optional). + pub rustversion: Option, + /// The initial version of the project (optional). + pub version: Option, + /// The website of the project (optional). + pub website: Option, +} + +impl FileGenerationParams { + /// Creates a default instance with default values for all fields. + /// Fields that are truly optional without a default are initialized as `None`. + pub fn default_params() -> Self { + Self { + author: Some("John Smith".to_string()), + build: Some("build.rs".to_string()), + categories: Some( + "[\"category1\",\"category2\",\"category3\"]" + .to_string(), + ), + description: Some( + "A Rust library for doing cool things".to_string(), + ), + documentation: Some( + "https://docs.rs/my_library".to_string(), + ), + edition: Some("2021".to_string()), + email: Some("john.smith@example.com".to_string()), + homepage: Some("https://my_library.rs".to_string()), + keywords: Some( + "[\"rust\",\"library\",\"cool\"]".to_string(), + ), + license: Some("MIT".to_string()), + name: Some("my_library".to_string()), + output: Some("my_library".to_string()), + readme: Some("README.md".to_string()), + repository: Some( + "https://github.com/example/my_library".to_string(), + ), + rustversion: Some("1.75.0".to_string()), + version: Some("0.1.0".to_string()), + website: Some("https://example.com/john-smith".to_string()), + } + } + /// Parses the command line arguments and returns a new instance of + /// the structure. + + /// Creates a new instance with default values. + pub fn new() -> Self { + Self::default_params() + } + /// Parses the command line arguments and returns a new instance of + /// the structure. + /// + /// # Arguments + /// * `args_str` - A string slice containing the command line arguments. + /// + /// # Errors + /// Returns an `Err` if the arguments are not in the expected format + /// or if mandatory arguments are missing. The error is a `String` + /// describing what went wrong. + /// + pub fn from_args(args_str: &str) -> Result { + let mut params = Self::new(); + let args: Vec<&str> = args_str.split_whitespace().collect(); + for arg in args { + let mut arg_parts = arg.splitn(2, ' '); + let arg_name = arg_parts + .next() + .ok_or_else(|| "Missing argument name".to_string())?; + let arg_value = arg_parts + .next() + .ok_or_else(|| "Missing argument value".to_string())?; + match arg_name { + "--author" => { + params.author = Some(arg_value.to_string()); + } + "--build" => params.build = Some(arg_value.to_string()), + "--categories" => { + params.categories = Some(arg_value.to_string()); + } + "--description" => { + params.description = Some(arg_value.to_string()); + } + "--documentation" => { + params.documentation = Some(arg_value.to_string()); + } + "--edition" => { + params.edition = Some(arg_value.to_string()); + } + "--email" => params.email = Some(arg_value.to_string()), + "--homepage" => { + params.homepage = Some(arg_value.to_string()); + } + "--keywords" => { + params.keywords = Some(arg_value.to_string()); + } + "--license" => { + params.license = Some(arg_value.to_string()); + } + "--name" => params.name = Some(arg_value.to_string()), + "--output" => { + params.output = Some(arg_value.to_string()); + } + "--readme" => { + params.readme = Some(arg_value.to_string()); + } + "--repository" => { + params.repository = Some(arg_value.to_string()); + } + "--rustversion" => { + params.rustversion = Some(arg_value.to_string()); + } + "--version" => { + params.version = Some(arg_value.to_string()); + } + "--website" => { + params.website = Some(arg_value.to_string()); + } + _ => (), + } + } + Ok(params) + } +} diff --git a/src/parser.rs b/src/parser.rs deleted file mode 100644 index 3bf44f5..0000000 --- a/src/parser.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright notice and licensing information. -// These lines indicate the copyright of the software and its licensing terms. -// SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. -// Copyright ยฉ 2024 LibMake. All rights reserved. - -/// A macro for getting a configuration field from a configuration file. -pub mod get_config_field; - -/// A macro for getting a field from a CSV file. -pub mod get_csv_field; - -/// A macro for getting a field from a JSON file. -pub mod get_json_field; - -/// A macro for getting a field from a TOML file. -pub mod get_yaml_field; diff --git a/src/utilities/directory.rs b/src/utilities/directory.rs new file mode 100644 index 0000000..e9a8bab --- /dev/null +++ b/src/utilities/directory.rs @@ -0,0 +1,209 @@ +// Copyright notice and licensing information. +// These lines indicate the copyright of the software and its licensing terms. +// SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. +// Copyright ยฉ 2024 LibMake. All rights reserved. + +use std::{ + error::Error, + fs::{self}, + path::{Path, PathBuf}, +}; +/// Ensures a directory exists, creating it if necessary. +/// +/// This function takes a reference to a `Path` object for a directory and a +/// human-readable name for the directory, and creates the directory if it +/// does not already exist. +/// +/// # Arguments +/// +/// * `dir` - A reference to a `Path` object for the directory. +/// * `name` - A human-readable name for the directory, used in error messages. +/// +/// # Returns +/// +/// * `Result<(), String>` - A result indicating success or failure. +/// - `Ok(())` if the directory exists or was created successfully. +/// - `Err(String)` if the directory does not exist and could not be created. +/// +/// # Example +/// +/// ``` +/// use libmake::utilities::directory::directory; +/// use std::path::Path; +/// use std::fs; +/// +/// // Create a "logs" directory if it doesn't exist +/// let dir = Path::new("logs"); +/// directory(dir, "logs").expect("Could not create logs directory"); +/// fs::remove_dir_all(dir).expect("Could not remove logs directory"); +/// ``` +/// +pub fn directory(dir: &Path, name: &str) -> Result { + if dir.exists() { + if !dir.is_dir() { + return Err( + format!("โŒ Error: {} is not a directory.", name) + ); + } + } else { + match fs::create_dir_all(dir) { + Ok(_) => {} + Err(e) => { + return Err(format!( + "โŒ Error: Cannot create {} directory: {}", + name, e + )) + } + } + } + Ok(String::new()) +} + +/// Moves the output directory to the public directory. +/// +/// This function takes a reference to a `Path` object for the output directory +/// and a string for the site name, and moves the output directory to the +/// public directory. +/// +/// # Arguments +/// +/// * `site_name` - A string for the site name. +/// * `out_dir` - A reference to a `Path` object for the output directory. +/// +/// # Returns +/// +/// * `Result<(), std::io::Error>` - A result indicating success or failure. +/// - `Ok(())` if the output directory was moved successfully. +/// - `Err(std::io::Error)` if the output directory could not be moved. +/// +pub fn move_output_directory( + site_name: &str, + out_dir: &Path, +) -> std::io::Result<()> { + println!("โฏ Moving output directory..."); + + let public_dir = Path::new("public"); + + if public_dir.exists() { + fs::remove_dir_all(public_dir)?; + } + + fs::create_dir(public_dir)?; + + let site_name = site_name.replace(' ', "_"); + let new_project_dir = public_dir.join(site_name); + fs::create_dir_all(&new_project_dir)?; + + fs::rename(out_dir, &new_project_dir)?; + + println!(" Done.\n"); + + Ok(()) +} + +/// Cleans up the directory at the given path. +/// +/// If the directory does not exist, this function does nothing. +/// +/// # Arguments +/// +/// * `directories` - An array of references to `Path` objects representing the +/// directories to be cleaned up. +/// +/// # Returns +/// +/// * `Result<(), Box>` - A result indicating success or failure. +/// - `Ok(())` if the directories were cleaned up successfully. +/// - `Err(Box)` if an error occurred during the cleanup process. +/// +pub fn cleanup_directory( + directories: &[&Path], +) -> Result<(), Box> { + for directory in directories { + if !directory.exists() { + continue; + } + + println!("\nโฏ Cleaning up directories"); + + fs::remove_dir_all(directory)?; + + println!(" Done.\n"); + } + + Ok(()) +} + +/// Creates a new directory at the given path. +/// +/// If the directory already exists, this function does nothing. +/// +/// # Arguments +/// +/// * `directories` - An array of references to `Path` objects representing the +/// directories to be created. +/// +/// # Returns +/// +/// * `Result<(), Box>` - A result indicating success or failure. +/// - `Ok(())` if the directories were created successfully. +/// - `Err(Box)` if an error occurred during the creation process. +/// +pub fn create_directory( + directories: &[&Path], +) -> Result<(), Box> { + for directory in directories { + if directory.exists() { + continue; + } + + fs::create_dir(directory)?; + } + + Ok(()) +} + +/// Truncates a path to only have a set number of path components. +/// +/// Will truncate a path to only show the last `length` components in a path. +/// If a length of `0` is provided, the path will not be truncated. +/// A value will only be returned if the path has been truncated. +/// +/// # Arguments +/// +/// * `path` - The path to truncate. +/// * `length` - The number of path components to keep. +/// +/// # Returns +/// +/// * An `Option` of the truncated path as a string. If the path was not truncated, `None` is returned. +pub fn truncate(path: &Path, length: usize) -> Option { + // Checks if the length is 0. If it is, returns `None`. + if length == 0 { + return None; + } + + // Creates a new PathBuf object to store the truncated path. + let mut truncated = PathBuf::new(); + + // Iterates over the components of the path in reverse order. + let mut count = 0; + while let Some(component) = path.components().next_back() { + // Adds the component to the truncated path. + truncated.push(component); + count += 1; + + // If the count reaches the desired length, breaks out of the loop. + if count == length { + break; + } + } + + // If the count is equal to the desired length, returns the truncated path as a string. + if count == length { + Some(truncated.to_string_lossy().to_string()) + } else { + // Otherwise, returns `None`. + None + } +} diff --git a/src/utilities/mod.rs b/src/utilities/mod.rs new file mode 100644 index 0000000..a40319e --- /dev/null +++ b/src/utilities/mod.rs @@ -0,0 +1,5 @@ +/// The `directory` module contains functions related to directory operations. +pub mod directory; + +/// The `uuid` module contains functions related to generating UUIDs. +pub mod uuid; diff --git a/src/utilities/uuid.rs b/src/utilities/uuid.rs new file mode 100644 index 0000000..c26c0f2 --- /dev/null +++ b/src/utilities/uuid.rs @@ -0,0 +1,28 @@ +// Copyright notice and licensing information. +// These lines indicate the copyright of the software and its licensing terms. +// SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. +// Copyright ยฉ 2024 LibMake. All rights reserved. + +// Import the Uuid type from the uuid crate +use uuid::Uuid; + +/// Generates a unique string. +/// +/// This function generates a new unique string using UUID version 4 (random). +/// +/// # Returns +/// +/// A string containing the generated unique identifier. +/// +/// # Examples +/// +/// ``` +/// use libmake::utilities::uuid::generate_unique_string; +/// +/// let unique_string = generate_unique_string(); +/// println!("Unique string: {}", unique_string); +/// ``` +pub fn generate_unique_string() -> String { + // Generate a new UUID v4 (random) and convert it to a string + Uuid::new_v4().to_string() +} diff --git a/src/utils.rs b/src/utils.rs index 23c99e8..ed3eb63 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -3,14 +3,13 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. // Copyright ยฉ 2024 LibMake. All rights reserved. -use serde_json::Value; -use serde_yaml::from_reader; -use serde_yaml::{from_str, to_string, Value as YamlValue}; -use std::env; -use std::fs; -use std::fs::File; -use std::io::BufReader; -use std::path::Path; +use crate::macro_get_field; +use std::{ + env, + fs::{self, File}, + io, + path::Path, +}; /// Reads a file and deserializes its content using the specified deserializer function. /// @@ -70,82 +69,16 @@ pub fn get_csv_field( }) } -/// Retrieves a specific field's value from a JSON file. -/// -/// # Arguments -/// -/// * `file_path` - An optional reference to the path of the JSON file. -/// * `field_name` - The name of the field to retrieve the value from. -/// -/// # Returns -/// -/// Returns a `Result>` containing the value of the specified field, or an error if one occurs. -/// -pub fn get_json_field( - file_path: Option<&str>, - field_name: &str, -) -> Result> { - file_path.map_or_else( - || Ok(String::new()), - |file_path| { - let current_dir = env::current_dir()?; - let file_path = Path::new(¤t_dir).join(file_path); - read_file(&file_path, |file| { - let json: Value = serde_json::from_reader(file)?; - let json_value = json[field_name].clone(); - let field_value = match json_value.as_str() { - Some(s) => s.to_string(), - None => { - let binding = json_value.to_string(); - let trimmed_binding = - binding.trim_matches('"').to_string(); - trimmed_binding - } - }; - Ok(field_value) - }) - }, - ) -} - -/// Retrieves a specific field's value from a YAML file. -/// -/// # Arguments -/// -/// * `file_path` - An optional reference to the path of the YAML file. -/// * `field_name` - The name of the field to retrieve the value from. -/// -/// # Returns -/// -/// Returns a `Result>` containing the value of the specified field, or an error if one occurs. -/// -pub fn get_yaml_field( - file_path: Option<&str>, - field_name: &str, -) -> Result> { - file_path.map_or_else( - || Ok(String::new()), - |file_path| { - let current_dir = env::current_dir()?; - let file_path = Path::new(¤t_dir).join(file_path); - read_file(&file_path, |file| { - let yaml: serde_yaml::Value = from_reader(file)?; - println!("YAML Value: {:?}", yaml); - let field_value = &yaml[field_name]; - println!("Field Value: {:?}", field_value); - let field_value_str = to_string(&field_value)?; - Ok(field_value_str.trim().to_string()) - }) - }, - ) -} +macro_get_field!(get_ini_field, serde_ini::from_read); +macro_get_field!(get_json_field, serde_json::from_reader); +macro_get_field!(get_yaml_field, serde_yaml::from_reader); /// Retrieves a specific field's value from a configuration file. /// /// # Arguments /// /// * `file_path` - An optional reference to the path of the configuration file. -/// * `file_format` - The format of the configuration file ("json" or "yaml"). +/// * `file_format` - The format of the configuration file ("json", "yaml", or "ini"). /// * `field_name` - The name of the field to retrieve the value from. /// /// # Returns @@ -160,38 +93,35 @@ pub fn get_config_field( // Ensure file_path is provided let file_path = file_path.ok_or("File path is not provided")?; - // Ensure file_format is provided and is either 'json' or 'yaml' + // Ensure file_format is provided and is either 'json', 'yaml', or 'ini' let format = file_format.ok_or("File format is not provided")?; match format { - "json" => { - // Read JSON file and extract field value - let file = File::open(file_path)?; - let reader = BufReader::new(file); - let json: Value = serde_json::from_reader(reader)?; - let field_value = json.get(field_name).ok_or("Field not found in JSON")?; - - // Handle JSON string values to remove surrounding quotes - match field_value.as_str() { - Some(s) => Ok(s.to_string()), - None => { - let s = field_value.to_string(); - Ok(s.trim_matches('"').to_string()) - } - } - }, - "yaml" => { - let yaml_str = fs::read_to_string(file_path)?; - let yaml_value: YamlValue = from_str(&yaml_str)?; - let field_value = yaml_value.get(field_name).ok_or("Field not found in YAML")?; - - // Convert the field_value to a string - let field_value_str = match field_value { - YamlValue::String(s) => s.clone(), - _ => to_string(field_value).unwrap(), - }; - - Ok(field_value_str) - } - _ => Err(format!("Unsupported file format: {}. Supported formats are 'json' and 'yaml'.", format).into()) + "ini" => get_ini_field(Some(file_path), field_name), + "json" => get_json_field(Some(file_path), field_name), + "yaml" => get_yaml_field(Some(file_path), field_name), + _ => Err(format!( + "Unsupported file format: {}. Supported formats are 'json', 'yaml', and 'ini'.", + format + ) + .into()), } } + +/// Creates a directory at the specified path. +/// +/// # Arguments +/// +/// * `path` - The path where the directory should be created. +/// +/// # Errors +/// +/// Returns an `io::Error` if the directory cannot be created. This could be due to +/// various reasons such as insufficient permissions, the directory already existing, +/// or other I/O-related errors. +/// +pub fn create_directory(path: &Path) -> io::Result<()> { + fs::create_dir(path).or_else(|e| match e.kind() { + io::ErrorKind::AlreadyExists => Ok(()), + _ => Err(e), + }) +} diff --git a/template/AUTHORS.tpl b/template/AUTHORS.tpl index 30854b1..7a438cf 100644 --- a/template/AUTHORS.tpl +++ b/template/AUTHORS.tpl @@ -1,3 +1,3 @@ # Authors -* [{author}]({email}) (Original Contributor) +* {author} ({email}) (Original Contributor) diff --git a/template/CONTRIBUTING.tpl b/template/CONTRIBUTING.tpl index a91e064..77ad647 100644 --- a/template/CONTRIBUTING.tpl +++ b/template/CONTRIBUTING.tpl @@ -1,81 +1,81 @@ -# Contributing to `{name}` - -Welcome! We're thrilled that you're interested in contributing to the -`{name}` library. Whether you're looking to evangelize, submit feedback, -or contribute code, we appreciate your involvement in making `{name}` a -better tool for everyone. Here's how you can get started. - -## Evangelize - -One of the simplest ways to help us out is by spreading the word about -{name}. We believe that a bigger, more involved community makes for a -better framework, and that better frameworks make the world a better -place. If you know people who might benefit from using {name}, please -let them know! - -## How to Contribute - -If you're interested in making a more direct contribution, there are -several ways you can help us improve {name}. Here are some guidelines -for submitting feedback, bug reports, and code contributions. - -### Feedback - -Your feedback is incredibly valuable to us, and we're always looking for -ways to make {name} better. If you have ideas, suggestions, or questions -about {name}, we'd love to hear them. Here's how you can provide -feedback: - -- Click [here][2] to submit a new feedback. -- Use a descriptive title that clearly summarizes your feedback. -- Provide a detailed description of the issue or suggestion. -- Be patient while we review and respond to your feedback. - -### Bug Reports - -If you encounter a bug while using {name}, please let us know so we can -fix it. Here's how you can submit a bug report: - -- Click [here][2] to submit a new issue. -- Use a descriptive title that clearly summarizes the bug. -- Provide a detailed description of the issue, including steps to - reproduce it. -- Be patient while we review and respond to your bug report. - -### Code Contributions - -If you're interested in contributing code to {name}, we're excited to -have your help! Here's what you need to know: - -#### Feature Requests - -If you have an idea for a new feature or improvement, we'd love to hear -it. Here's how you can contribute code for a new feature to {name}: - -- Fork the repo. -- Clone the {name}[1] repo by running: - `git clone {repository}` -- Edit files in the `src/` folder. The `src/` folder contains the source - code for {name}. -- Submit a pull request, and we'll review and merge your changes if they - fit with our vision for {name}. - -#### Submitting Code - -If you've identified a bug or have a specific code improvement in mind, -we welcome your pull requests. Here's how to submit your code changes: - -- Fork the repo. -- Clone the {name} repo by running: - `git clone {repository}` -- Edit files in the `src/` folder. The `src/` folder contains the source - code for {name}. -- Submit a pull request, and we'll review and merge your changes if they - fit with our vision for {name}. - -We hope that this guide has been helpful in explaining how you can -contribute to {name}. Thank you for your interest and involvement in our -project! - -[1]: {repository} -[2]: {repository}/issues/newHTTP/2 416 \ No newline at end of file +# Contributing to `{name}` + +Welcome! We're thrilled that you're interested in contributing to the +`{name}` library. Whether you're looking to evangelize, submit feedback, +or contribute code, we appreciate your involvement in making `{name}` a +better tool for everyone. Here's how you can get started. + +## Evangelize + +One of the simplest ways to help us out is by spreading the word about +{name}. We believe that a bigger, more involved community makes for a +better framework, and that better frameworks make the world a better +place. If you know people who might benefit from using {name}, please +let them know! + +## How to Contribute + +If you're interested in making a more direct contribution, there are +several ways you can help us improve {name}. Here are some guidelines +for submitting feedback, bug reports, and code contributions. + +### Feedback + +Your feedback is incredibly valuable to us, and we're always looking for +ways to make {name} better. If you have ideas, suggestions, or questions +about {name}, we'd love to hear them. Here's how you can provide +feedback: + +- Click [here][2] to submit a new feedback. +- Use a descriptive title that clearly summarizes your feedback. +- Provide a detailed description of the issue or suggestion. +- Be patient while we review and respond to your feedback. + +### Bug Reports + +If you encounter a bug while using {name}, please let us know so we can +fix it. Here's how you can submit a bug report: + +- Click [here][2] to submit a new issue. +- Use a descriptive title that clearly summarizes the bug. +- Provide a detailed description of the issue, including steps to + reproduce it. +- Be patient while we review and respond to your bug report. + +### Code Contributions + +If you're interested in contributing code to {name}, we're excited to +have your help! Here's what you need to know: + +#### Feature Requests + +If you have an idea for a new feature or improvement, we'd love to hear +it. Here's how you can contribute code for a new feature to {name}: + +- Fork the repo. +- Clone the {name}[1] repo by running: + `git clone {repository}` +- Edit files in the `src/` folder. The `src/` folder contains the source + code for {name}. +- Submit a pull request, and we'll review and merge your changes if they + fit with our vision for {name}. + +#### Submitting Code + +If you've identified a bug or have a specific code improvement in mind, +we welcome your pull requests. Here's how to submit your code changes: + +- Fork the repo. +- Clone the {name} repo by running: + `git clone {repository}` +- Edit files in the `src/` folder. The `src/` folder contains the source + code for {name}. +- Submit a pull request, and we'll review and merge your changes if they + fit with our vision for {name}. + +We hope that this guide has been helpful in explaining how you can +contribute to {name}. Thank you for your interest and involvement in our +project! + +[1]: {repository} +[2]: {repository}/issues/new diff --git a/template/Cargo.tpl b/template/Cargo.tpl index 71ddc5c..2185f26 100644 --- a/template/Cargo.tpl +++ b/template/Cargo.tpl @@ -1,32 +1,27 @@ [package] -authors = ["{author} <{email}>"] -build = "{build}" -categories = [{categories}] -description = "{description}" -documentation = "{documentation}" -edition = "{edition}" -exclude = [ - "/.git/*", - "/.github/*", - "/.gitignore", - "/.vscode/*" - ] -homepage = "{homepage}" -keywords = ["{keywords}"] -license = "{license}" +authors = [{author}] +build = {build} +categories = {categories} +description = {description} +documentation = {documentation} +edition = {edition} +exclude = ["/.git/*", "/.github/*", "/.gitignore", "/.vscode/*"] +homepage = {homepage} +keywords = {keywords} +license = {license} name = "{name}" -readme = "{readme}" +readme = {readme} repository = "{repository}" -rust-version = "{rustversion}" -version = "{version}" +rust-version = {rustversion} +version = {version} include = [ + "/CONTRIBUTING.md", + "/LICENSE-APACHE", + "/LICENSE-MIT", "/benches/**", "/build.rs", "/Cargo.toml", - "/CONTRIBUTING.md", "/examples/**", - "/LICENSE-APACHE", - "/LICENSE-MIT", "/README.md", "/src/**", "/tests/**" @@ -46,7 +41,7 @@ dtt = "0.0.5" env_logger = "0.11.3" rlg = "0.0.3" serde = { version = "1.0.197", features = ["derive"] } -serde_json = "1.0.114" +serde_json = "1.0.115" serde_yaml = "0.9.33" toml = "0.8.12" vrd = "0.0.6" diff --git a/template/README.tpl b/template/README.tpl index acb539e..93a31c0 100644 --- a/template/README.tpl +++ b/template/README.tpl @@ -18,17 +18,9 @@ align="right"
-[![Made With Rust][made-with-rust-badge]][5] -[![Crates.io][crates-badge]][7] -[![Lib.rs][libs-badge]][9] -[![Docs.rs][docs-badge]][8] -[![License][license-badge]][2] - -โ€ข [Website][0] -โ€ข [Documentation][8] -โ€ข [Report Bug][3] -โ€ข [Request Feature][3] -โ€ข [Contributing Guidelines][4] +[![Made With Rust][made-with-rust-badge]][04] [![Crates.io][crates-badge]][06] [![Lib.rs][libs-badge]][08] [![Docs.rs][docs-badge]][07] [![License][license-badge]][01] + +โ€ข [Website][00] โ€ข [Documentation][07] โ€ข [Report Bug][02] โ€ข [Request Feature][02] โ€ข [Contributing Guidelines][03]
@@ -54,7 +46,7 @@ It takes just a few minutes to get up and running with `{name}`. To install `{name}`, you need to have the Rust toolchain installed on your machine. You can install the Rust toolchain by following the -instructions on the [Rust website][13]. +instructions on the [Rust website][12]. Once you have the Rust toolchain installed, you can install `{name}` using the following command: @@ -63,12 +55,6 @@ using the following command: cargo install {name} ``` -You can then run the help command to see the available options: - -```shell -{name} --help -``` - ### Requirements The minimum supported Rust toolchain version is currently Rust @@ -106,13 +92,13 @@ The minimum supported Rust toolchain version is currently Rust | โœ… | macOS | aarch64-apple-darwin | 64-bit macOS (10.7 Lion or later) | | โœ… | Windows | aarch64-pc-windows-msvc | 64-bit Windows (7 or later) | -The [GitHub Actions][10] shows the platforms in which the `{name}` +The [GitHub Actions][09] shows the platforms in which the `{name}` library tests are run. ### Documentation -**Info:** Please check out our [website][0] for more information. You can find our documentation on [docs.rs][8], [lib.rs][9] and -[crates.io][7]. +**Info:** Please check out our [website][00] for more information. You can find our documentation on [docs.rs][07], [lib.rs][08] and +[crates.io][06]. ## Usage ๐Ÿ“– @@ -121,7 +107,7 @@ To use the `{name}` library in your project, add the following to your ```toml [dependencies] -{name} = "{version}" +{name} = {version} ``` Add the following to your `main.rs` file: @@ -142,13 +128,13 @@ To run the examples, clone the repository and run the following command in your terminal from the project root directory. ```shell -cargo run --example {name} +cargo run --example example ``` ## Semantic Versioning Policy ๐Ÿšฅ For transparency into our release cycle and in striving to maintain -backward compatibility, `{name}` follows [semantic versioning][6]. +backward compatibility, `{name}` follows [semantic versioning][05]. ## License ๐Ÿ“ @@ -157,10 +143,10 @@ The project is licensed under the terms of {license}. ## Contribution ๐Ÿค We welcome all people who want to contribute. Please see the -[contributing instructions][4] for more information. +[contributing instructions][03] for more information. Contributions in any form (issues, pull requests, etc.) to this project -must adhere to the [Rust's Code of Conduct][11]. +must adhere to the [Rust's Code of Conduct][10]. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the @@ -169,25 +155,25 @@ additional terms or conditions. ## Acknowledgements ๐Ÿ’™ -A big thank you to all the awesome contributors of [{name}][5] for their +A big thank you to all the awesome contributors of [{name}][04] for their help and support. -A special thank you goes to the [Rust Reddit][12] community for +A special thank you goes to the [Rust Reddit][11] community for providing a lot of useful suggestions on how to improve this project. -[0]: {website} -[2]: http://opensource.org/licenses/MIT -[3]: {repository}/{name}/issues -[4]: {repository}/{name}/blob/main/CONTRIBUTING.md -[5]: {repository}/{name}/graphs/contributors -[6]: http://semver.org/ -[7]: https://crates.io/crates/{name} -[8]: https://docs.rs/{name} -[9]: https://lib.rs/crates/{name} -[10]: {repository}/{name}/actions -[11]: https://www.rust-lang.org/policies/code-of-conduct -[12]: https://www.reddit.com/r/rust/ -[13]: https://www.rust-lang.org/learn/get-started +[00]: {website} "Website of {name}" +[01]: https://opensource.org/license/apache-2-0/ "Apache License, Version 2.0" +[02]: {repository}/{name}/issues "Issues page of {name}" +[03]: {repository}/{name}/blob/main/CONTRIBUTING.md "Contributing guidelines" +[04]: {repository}/{name}/graphs/contributors "Contributors of {name}" +[05]: http://semver.org/ "Semantic Versioning" +[06]: https://crates.io/crates/{name} "Crates.io page of {name}" +[07]: https://docs.rs/{name} "Docs.rs page of {name}" +[08]: https://lib.rs/crates/{name} "Lib.rs page of {name}" +[09]: {repository}/{name}/actions "GitHub Actions page of {name}" +[10]: https://www.rust-lang.org/policies/code-of-conduct "Rust's Code of Conduct" +[11]: https://www.reddit.com/r/rust/ "Rust Reddit community" +[12]: https://www.rust-lang.org/learn/get-started "Rust installation page" [crates-badge]: https://img.shields.io/crates/v/{name}.svg?style=for-the-badge 'Crates.io badge' [divider]: https://kura.pro/common/images/elements/divider.svg "divider" diff --git a/template/TEMPLATE.tpl b/template/TEMPLATE.tpl index a46166b..6acc3fe 100644 --- a/template/TEMPLATE.tpl +++ b/template/TEMPLATE.tpl @@ -1,68 +1,59 @@ - - - - - - -# {name} - -{description} - - -
- - -[![Made With Rust][made-with-rust-badge]][5] -[![Crates.io][crates-badge]][7] -[![Lib.rs][libs-badge]][9] -[![Docs.rs][docs-badge]][8] -[![License][license-badge]][2] - -โ€ข [Website][0] -โ€ข [Documentation][8] -โ€ข [Report Bug][3] -โ€ข [Request Feature][3] -โ€ข [Contributing Guidelines][4] - - -
- - -![divider][divider] - -## Overview ๐Ÿ“– - -{description} - -## Features โœจ - -- Feature 1 -- Feature 2 -- Feature 3 - -## Changelog ๐Ÿ“š - -- - -[0]: {website} -[2]: http://opensource.org/licenses/MIT -[3]: {repository}/{name}/issues -[4]: {repository}/{name}/blob/main/CONTRIBUTING.md -[5]: {repository}/{name}/graphs/contributors -[7]: https://crates.io/crates/{name} -[8]: https://docs.rs/{name} -[9]: https://lib.rs/crates/{name} - -[banner]: https://via.placeholder.com/1500x500.png/000000/FFFFFF?text={name} "{name}'s banner" -[crates-badge]: https://img.shields.io/crates/v/{name}.svg?style=for-the-badge 'Crates.io badge' -[divider]: https://via.placeholder.com/1024x1.png/d8dee4/FFFFFF?text=โˆ’ "{name}'s divider" -[docs-badge]: https://img.shields.io/docsrs/{name}.svg?style=for-the-badge 'Docs.rs badge' -[libs-badge]: https://img.shields.io/badge/lib.rs-v{version}-orange.svg?style=for-the-badge 'Lib.rs badge' -[license-badge]: https://img.shields.io/crates/l/{name}.svg?style=for-the-badge 'License badge' -[made-with-rust-badge]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust badge' \ No newline at end of file + + +{name}'s logo + + + +# {name} + +{description} + + +
+ + +[![Made With Rust][made-with-rust-badge]][04] [![Crates.io][crates-badge]][05] [![Lib.rs][libs-badge]][07] [![Docs.rs][docs-badge]][06] [![License][license-badge]][01] + +โ€ข [Website][00] โ€ข [Documentation][06] โ€ข [Report Bug][02] โ€ข [Request Feature][02] โ€ข [Contributing Guidelines][03] + + +
+ + +![divider][divider] + +## Overview ๐Ÿ“– + +{description} + +## Features โœจ + +- Feature 1 +- Feature 2 +- Feature 3 + +## Changelog ๐Ÿ“š + +- + +[00]: {website} "Website of {name}" +[01]: https://opensource.org/license/apache-2-0/ "Apache License, Version 2.0" +[02]: {repository}/{name}/issues "Issues page of {name}" +[03]: {repository}/{name}/blob/main/CONTRIBUTING.md "Contributing guidelines of {name}" +[04]: {repository}/{name}/graphs/contributors "Contributors of {name}" +[05]: https://crates.io/crates/{name} "Crates.io page of {name}" +[06]: https://docs.rs/{name} "Docs.rs page of {name}" +[07]: https://lib.rs/crates/{name} "Lib.rs page of {name}" + +[crates-badge]: https://img.shields.io/crates/v/{name}.svg?style=for-the-badge 'Crates.io badge' +[divider]: https://via.placeholder.com/1024x1.png/d8dee4/FFFFFF?text=โˆ’ "{name}'s divider" +[docs-badge]: https://img.shields.io/docsrs/{name}.svg?style=for-the-badge 'Docs.rs badge' +[libs-badge]: https://img.shields.io/badge/lib.rs-v{version}-orange.svg?style=for-the-badge 'Lib.rs badge' +[license-badge]: https://img.shields.io/crates/l/{name}.svg?style=for-the-badge 'License badge' +[made-with-rust-badge]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust badge' diff --git a/template/ci.tpl b/template/ci.tpl index 772e15d..27cd045 100644 --- a/template/ci.tpl +++ b/template/ci.tpl @@ -1,486 +1,486 @@ -name: โฏ {name} release - -on: - pull_request: - branches: - - main - - 'feat/*' - push: - branches: - - main - - 'feat/*' - -jobs: - # This job checks a local package and all of its dependencies for - # errors. - check: - name: โฏ Check ๐Ÿ’ต - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - rust: stable - target: x86_64-unknown-linux-gnu - os: ubuntu-latest - - steps: - # Check out the repository code - - name: Checkout sources - id: checkout - uses: actions/checkout@v4 - - # Install the stable Rust toolchain - - name: Install stable toolchain - id: install-toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - - # Cache dependencies to speed up subsequent builds - - name: Cache dependencies - id: cache-dependencies - uses: actions/cache@v3 - with: - path: ~/.cargo - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo- - - # Run cargo check to check for errors - - uses: actions-rs/cargo@v1 - with: - command: check - args: --all-targets --workspace --all-features - - # This job runs the tests for the project. - test: - name: โฏ Test ๐Ÿงช - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - rust: stable - target: x86_64-unknown-linux-gnu - - steps: - # Check out the repository code - - name: Checkout sources - id: checkout - uses: actions/checkout@v4 - - # Install the stable Rust toolchain - - name: Install stable toolchain - id: install-toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ matrix.rust }} - - # Cache dependencies to speed up subsequent builds - - name: Cache dependencies - id: cache-dependencies - uses: actions/cache@v3 - with: - path: ~/.cargo - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo- - - # Run cargo hack to check for errors - - name: Install cargo-hack - uses: taiki-e/install-action@cargo-hack - id: install-cargo-hack - - - run: cargo test --all-targets --workspace --all-features - - # This job runs the tests for the project. - coverage: - name: โฏ Coverage ๐Ÿ“Š - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - runs-on: ubuntu-latest - strategy: - matrix: - include: - - rust: stable - target: x86_64-unknown-linux-gnu - - steps: - # Check out the repository code - - name: Checkout sources - id: checkout - uses: actions/checkout@v4 - - # Install the stable Rust toolchain - - name: Install stable toolchain - id: install-toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ matrix.rust }} - override: true - components: llvm-tools-preview - - # Cache dependencies to speed up subsequent builds - - name: Cache dependencies - id: cache-dependencies - uses: actions/cache@v3 - with: - path: ~/.cargo - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo- - - # Install grcov - - name: Install grcov - run: | - mkdir -p "${HOME}/.local/bin" - curl -sL https://github.com/mozilla/grcov/releases/download/v0.8.18/grcov-x86_64-unknown-linux-gnu.tar.bz2 | tar jxf - -C "${HOME}/.local/bin" - echo "$HOME/.local/bin" >> $GITHUB_PATH - - # Use grcov to generate a coverage report - - name: Generate coverage report - id: coverage - uses: actions-rs/cargo@v1 - with: - command: xtask - args: coverage - - # Upload the coverage report to codecov - - name: Upload coverage report to codecov - id: codecov - uses: codecov/codecov-action@v3 - with: - files: coverage/*.lcov - - lints: - name: โฏ Lints ๐Ÿงน - runs-on: ubuntu-latest - strategy: - matrix: - include: - - rust: stable - target: x86_64-unknown-linux-gnu - steps: - # Check out the repository code - - name: Checkout sources - id: checkout - uses: actions/checkout@v4 - with: - submodules: true - - # Install the stable Rust toolchain - - name: Install stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - components: clippy - - # Cache dependencies to speed up subsequent builds - - name: Cache dependencies - uses: actions/cache@v3 - with: - path: ~/.cargo - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo- - - # Run cargo clippy to check for linting errors - - name: Run cargo clippy - if: github.ref == !github.event.check_run.conclusion - uses: actions-rs/cargo@v1 - with: - command: clippy - args: --all-targets --all-features -- -D warnings - - # Run Cargo Format for the code style - - name: Run Cargo Format - id: run-check-format - if: github.ref == !github.event.check_run.conclusion - run: | - cargo check --all --all-features --workspace --verbose - - # Run cargo clippy to check for linting errors - - name: Run Clippy - id: run-check-clippy - if: github.ref == !github.event.check_run.conclusion - run: | - cargo clippy --all-targets --all-features --workspace -- -D warnings - - - build: - # This job builds the project for all the targets and generates a - # release artifact that contains the binaries for all the targets. - name: โฏ Build ๐Ÿ›  - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - strategy: - fail-fast: false - matrix: - target: - # List of targets: https://doc.rust-lang.org/nightly/rustc/platform-support.html - - # FreeBSD targets ๐Ÿฌ - - x86_64-unknown-freebsd # 64-bit FreeBSD on x86-64 โœ… Tested - - # Linux targets ๐Ÿง - - aarch64-unknown-linux-gnu # 64-bit Linux systems on ARM architecture โœ… Tested - - aarch64-unknown-linux-musl # 64-bit Linux systems on ARM architecture โœ… Tested - - arm-unknown-linux-gnueabi # ARMv6 Linux (kernel 3.2, glibc 2.17) โœ… Tested - - armv7-unknown-linux-gnueabihf # ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17) โœ… Tested - - i686-unknown-linux-gnu # 32-bit Linux (kernel 3.2+, glibc 2.17+) โœ… Tested - - i686-unknown-linux-musl # 32-bit Linux (kernel 3.2+, musl libc) โœ… Tested - - x86_64-unknown-linux-gnu # 64-bit Linux (kernel 2.6.32+, glibc 2.11+) โœ… Tested - - x86_64-unknown-linux-musl # 64-bit Linux (kernel 2.6.32+, musl libc) โœ… Tested - - # macOS targets ๐ŸŽ - - aarch64-apple-darwin # 64-bit macOS on Apple Silicon โœ… Tested - - x86_64-apple-darwin # 64-bit macOS (10.7 Lion or later) โœ… Tested - - # Illumos targets ๐ŸŒž - - x86_64-unknown-illumos # 64-bit Illumos on x86-64 โœ… Tested - - include: - # FreeBSD targets ๐Ÿฌ - - target: x86_64-unknown-freebsd - os: ubuntu-latest - cross: true - - # Linux targets ๐Ÿง - - target: aarch64-unknown-linux-gnu - os: ubuntu-latest - cross: true - - target: aarch64-unknown-linux-musl - os: ubuntu-latest - cross: true - - target: arm-unknown-linux-gnueabi - os: ubuntu-latest - cross: true - - target: armv7-unknown-linux-gnueabihf - os: ubuntu-latest - cross: true - - target: i686-unknown-linux-gnu - os: ubuntu-latest - cross: true - - target: i686-unknown-linux-musl - os: ubuntu-latest - cross: true - - target: x86_64-unknown-linux-gnu - os: ubuntu-latest - cross: true - - target: x86_64-unknown-linux-musl - os: ubuntu-latest - cross: true - - # Illumos targets ๐ŸŒž - - target: x86_64-unknown-illumos - os: ubuntu-latest - cross: true - - # macOS targets ๐ŸŽ - - target: aarch64-apple-darwin - os: macos-latest - cross: true - - target: x86_64-apple-darwin - os: macos-latest - cross: true - - runs-on: ${{ matrix.os }} - - steps: - # Check out the repository code - - name: Checkout sources - id: checkout - uses: actions/checkout@v4 - - # Install the stable Rust toolchain - - name: Install stable toolchain - id: install-toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - - # Cache dependencies to speed up subsequent builds - - name: Cache dependencies - id: cache-dependencies - uses: actions/cache@v3 - with: - path: ~/.cargo - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo- - - # Install the targets for the cross compilation toolchain - - name: Install target - id: install-target - run: rustup target add ${{ matrix.target }} - - # Update the version number based on the Cargo.toml file - - name: Update version number - id: update-version - run: | - NEW_VERSION=$(grep version Cargo.toml | sed -n 2p | cut -d '"' -f 2) - echo "VERSION=$NEW_VERSION" >> $GITHUB_ENV - shell: /bin/bash -e {0} - - # Install the cross compilation toolchain - - name: Install Cross - id: install-cross - run: | - # Install cross - cargo install cross - # Clean the build artifacts - cargo clean --verbose - shell: /bin/bash -e {0} - - # Build the targets - - name: Build targets - id: build-targets - uses: actions-rs/cargo@v1 - with: - use-cross: true - command: build - args: --verbose --workspace --release --target ${{ matrix.target }} - - # Package the binary for each target - - name: Package the binary - id: package-binary - run: | - mkdir -p target/package - tar czf target/package/${{ matrix.target }}.tar.gz -C target/${{ matrix.target }}/release . - echo "${{ matrix.target }}.tar.gz=target/package/${{ matrix.target }}.tar.gz" >> $GITHUB_ENV - - # Upload the binary for each target - - name: Upload the binary - id: upload-binary - uses: actions/upload-artifact@v2 - with: - name: ${{ matrix.target }}.tar.gz - path: ${{ env[format('{0}.tar.gz', matrix.target)] }} - - # Release the binary to GitHub Releases - release: - name: โฏ Release ๐Ÿš€ - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - needs: build - runs-on: ubuntu-latest - steps: - # Check out the repository code - - name: Checkout sources - uses: actions/checkout@v4 - - # Install the stable Rust toolchain - - name: Install stable toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - - # Update the version number based on the Cargo.toml file - - name: Update version number - run: | - NEW_VERSION=$(grep version Cargo.toml | sed -n 2p | cut -d '"' -f 2) - echo "VERSION=$NEW_VERSION" >> $GITHUB_ENV - shell: /bin/bash -e {0} - - # Cache dependencies to speed up subsequent builds - - name: Cache dependencies - uses: actions/cache@v3 - with: - path: ~/.cargo - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo- - - # Download the artifacts from the build job - - name: Download artifacts - run: | - for target in x86_64-unknown-freebsd aarch64-unknown-linux-gnu aarch64-unknown-linux-musl arm-unknown-linux-gnueabi armv7-unknown-linux-gnueabihf i686-unknown-linux-gnu i686-unknown-linux-musl x86_64-unknown-linux-gnu x86_64-unknown-linux-musl aarch64-apple-darwin x86_64-apple-darwin x86_64-unknown-illumos; do - echo "Downloading $target artifact" - name="${target}.tar.gz" - echo "Artifact name: $name" - mkdir -p target/package - curl -sSL -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/vnd.github.v3+json" -L "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}/artifacts/${name}" -o "target/package/${name}" - done - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - RUN_ID: ${{ github.event.workflow_run.id }} - - # Generate the changelog based on git log and template file - - name: Generate Changelog - run: | - # Append version information to CHANGELOG.md - echo "## Release v${{ env.VERSION }} - $(date +'%Y-%m-%d')" >> ${{ github.workspace }}/CHANGELOG.md - # Copy content of template file to CHANGELOG.md - cat TEMPLATE.md >> ${{ github.workspace }}/CHANGELOG.md - # Append git log to CHANGELOG.md - echo "$(git log --pretty=format:'%s' --reverse $(git describe --tags --abbrev=0)..HEAD)" >> ${{ github.workspace }}/CHANGELOG.md - # Append empty line to CHANGELOG.md - echo "" >> ${{ github.workspace }}/CHANGELOG.md - - # Append the artifact links to the changelog - - name: Append Artifact Links - run: | - echo "" >> ${{ github.workspace }}/CHANGELOG.md - echo "## Artifacts ๐ŸŽ" >> ${{ github.workspace }}/CHANGELOG.md - for filename in target/package/*.tar.gz; do - link="$(basename $filename)" - echo "* [$link](${{ github.server_url }}/${{ github.repository }}/releases/download/v${{ env.VERSION }}/$link)" >> ${{ github.workspace }}/CHANGELOG.md - done - - # Create the release on GitHub Releases - - name: Create Release - id: create-release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: v${{ env.VERSION }} - release_name: {name} ๐Ÿฆ€ v${{ env.VERSION }} - body_path: ${{ github.workspace }}/CHANGELOG.md - draft: true - prerelease: false - - # Publish the release to Crates.io automatically - crate: - name: โฏ Crate.io ๐Ÿฆ€ - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - needs: release - runs-on: ubuntu-latest - - steps: - # Check out the repository code - - name: Checkout - uses: actions/checkout@v4 - - # Install the stable Rust toolchain - - name: Install stable toolchain - id: install-toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - - # Cache dependencies to speed up subsequent builds - - name: Cache dependencies - id: cache-dependencies - uses: actions/cache@v2 - with: - path: /home/runner/.cargo/registry/index/ - key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo-index- - - # Update the version number based on the Cargo.toml file - - name: Update version number - id: update-version - run: | - NEW_VERSION=$(grep version Cargo.toml | sed -n 2p | cut -d '"' -f 2) - echo "VERSION=$NEW_VERSION" >> $GITHUB_ENV - shell: /bin/bash -e {0} - - # Publish the Rust library to Crate.io - - name: Publish Library to Crate.io - id: publish-library - uses: actions-rs/cargo@v1 - env: - CARGO_API_TOKEN: ${{ secrets.CARGO_API_TOKEN }} - with: - use-cross: true - command: publish - args: --dry-run --verbose --token "${CARGO_API_TOKEN}" \ No newline at end of file +name: โฏ {name} release + +on: + pull_request: + branches: + - main + - 'feat/*' + push: + branches: + - main + - 'feat/*' + +jobs: + # This job checks a local package and all of its dependencies for + # errors. + check: + name: โฏ Check ๐Ÿ’ต + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - rust: stable + target: x86_64-unknown-linux-gnu + os: ubuntu-latest + + steps: + # Check out the repository code + - name: Checkout sources + id: checkout + uses: actions/checkout@v4 + + # Install the stable Rust toolchain + - name: Install stable toolchain + id: install-toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + + # Cache dependencies to speed up subsequent builds + - name: Cache dependencies + id: cache-dependencies + uses: actions/cache@v3 + with: + path: ~/.cargo + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo- + + # Run cargo check to check for errors + - uses: actions-rs/cargo@v1 + with: + command: check + args: --all-targets --workspace --all-features + + # This job runs the tests for the project. + test: + name: โฏ Test ๐Ÿงช + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - rust: stable + target: x86_64-unknown-linux-gnu + + steps: + # Check out the repository code + - name: Checkout sources + id: checkout + uses: actions/checkout@v4 + + # Install the stable Rust toolchain + - name: Install stable toolchain + id: install-toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + + # Cache dependencies to speed up subsequent builds + - name: Cache dependencies + id: cache-dependencies + uses: actions/cache@v3 + with: + path: ~/.cargo + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo- + + # Run cargo hack to check for errors + - name: Install cargo-hack + uses: taiki-e/install-action@cargo-hack + id: install-cargo-hack + + - run: cargo test --all-targets --workspace --all-features + + # This job runs the tests for the project. + coverage: + name: โฏ Coverage ๐Ÿ“Š + if: github.ref == 'refs/heads/main' && github.event_name == 'push' + runs-on: ubuntu-latest + strategy: + matrix: + include: + - rust: stable + target: x86_64-unknown-linux-gnu + + steps: + # Check out the repository code + - name: Checkout sources + id: checkout + uses: actions/checkout@v4 + + # Install the stable Rust toolchain + - name: Install stable toolchain + id: install-toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + override: true + components: llvm-tools-preview + + # Cache dependencies to speed up subsequent builds + - name: Cache dependencies + id: cache-dependencies + uses: actions/cache@v3 + with: + path: ~/.cargo + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo- + + # Install grcov + - name: Install grcov + run: | + mkdir -p "${HOME}/.local/bin" + curl -sL https://github.com/mozilla/grcov/releases/download/v0.8.19/grcov-x86_64-unknown-linux-gnu.tar.bz2 | tar jxf - -C "${HOME}/.local/bin" + echo "$HOME/.local/bin" >> $GITHUB_PATH + + # Use grcov to generate a coverage report + - name: Generate coverage report + id: coverage + uses: actions-rs/cargo@v1 + with: + command: xtask + args: coverage + + # Upload the coverage report to codecov + - name: Upload coverage report to codecov + id: codecov + uses: codecov/codecov-action@v3 + with: + files: coverage/*.lcov + + lints: + name: โฏ Lints ๐Ÿงน + runs-on: ubuntu-latest + strategy: + matrix: + include: + - rust: stable + target: x86_64-unknown-linux-gnu + steps: + # Check out the repository code + - name: Checkout sources + id: checkout + uses: actions/checkout@v4 + with: + submodules: true + + # Install the stable Rust toolchain + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: clippy + + # Cache dependencies to speed up subsequent builds + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: ~/.cargo + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo- + + # Run cargo clippy to check for linting errors + - name: Run cargo clippy + if: github.ref == !github.event.check_run.conclusion + uses: actions-rs/cargo@v1 + with: + command: clippy + args: --all-targets --all-features -- -D warnings + + # Run Cargo Format for the code style + - name: Run Cargo Format + id: run-check-format + if: github.ref == !github.event.check_run.conclusion + run: | + cargo check --all --all-features --workspace --verbose + + # Run cargo clippy to check for linting errors + - name: Run Clippy + id: run-check-clippy + if: github.ref == !github.event.check_run.conclusion + run: | + cargo clippy --all-targets --all-features --workspace -- -D warnings + + + build: + # This job builds the project for all the targets and generates a + # release artifact that contains the binaries for all the targets. + name: โฏ Build ๐Ÿ›  + if: github.ref == 'refs/heads/main' && github.event_name == 'push' + strategy: + fail-fast: false + matrix: + target: + # List of targets: https://doc.rust-lang.org/nightly/rustc/platform-support.html + + # FreeBSD targets ๐Ÿฌ + - x86_64-unknown-freebsd # 64-bit FreeBSD on x86-64 โœ… Tested + + # Linux targets ๐Ÿง + - aarch64-unknown-linux-gnu # 64-bit Linux systems on ARM architecture โœ… Tested + - aarch64-unknown-linux-musl # 64-bit Linux systems on ARM architecture โœ… Tested + - arm-unknown-linux-gnueabi # ARMv6 Linux (kernel 3.2, glibc 2.17) โœ… Tested + - armv7-unknown-linux-gnueabihf # ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17) โœ… Tested + - i686-unknown-linux-gnu # 32-bit Linux (kernel 3.2+, glibc 2.17+) โœ… Tested + - i686-unknown-linux-musl # 32-bit Linux (kernel 3.2+, musl libc) โœ… Tested + - x86_64-unknown-linux-gnu # 64-bit Linux (kernel 2.6.32+, glibc 2.11+) โœ… Tested + - x86_64-unknown-linux-musl # 64-bit Linux (kernel 2.6.32+, musl libc) โœ… Tested + + # macOS targets ๐ŸŽ + - aarch64-apple-darwin # 64-bit macOS on Apple Silicon โœ… Tested + - x86_64-apple-darwin # 64-bit macOS (10.7 Lion or later) โœ… Tested + + # Illumos targets ๐ŸŒž + - x86_64-unknown-illumos # 64-bit Illumos on x86-64 โœ… Tested + + include: + # FreeBSD targets ๐Ÿฌ + - target: x86_64-unknown-freebsd + os: ubuntu-latest + cross: true + + # Linux targets ๐Ÿง + - target: aarch64-unknown-linux-gnu + os: ubuntu-latest + cross: true + - target: aarch64-unknown-linux-musl + os: ubuntu-latest + cross: true + - target: arm-unknown-linux-gnueabi + os: ubuntu-latest + cross: true + - target: armv7-unknown-linux-gnueabihf + os: ubuntu-latest + cross: true + - target: i686-unknown-linux-gnu + os: ubuntu-latest + cross: true + - target: i686-unknown-linux-musl + os: ubuntu-latest + cross: true + - target: x86_64-unknown-linux-gnu + os: ubuntu-latest + cross: true + - target: x86_64-unknown-linux-musl + os: ubuntu-latest + cross: true + + # Illumos targets ๐ŸŒž + - target: x86_64-unknown-illumos + os: ubuntu-latest + cross: true + + # macOS targets ๐ŸŽ + - target: aarch64-apple-darwin + os: macos-latest + cross: true + - target: x86_64-apple-darwin + os: macos-latest + cross: true + + runs-on: ${{ matrix.os }} + + steps: + # Check out the repository code + - name: Checkout sources + id: checkout + uses: actions/checkout@v4 + + # Install the stable Rust toolchain + - name: Install stable toolchain + id: install-toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + + # Cache dependencies to speed up subsequent builds + - name: Cache dependencies + id: cache-dependencies + uses: actions/cache@v3 + with: + path: ~/.cargo + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo- + + # Install the targets for the cross compilation toolchain + - name: Install target + id: install-target + run: rustup target add ${{ matrix.target }} + + # Update the version number based on the Cargo.toml file + - name: Update version number + id: update-version + run: | + NEW_VERSION=$(grep version Cargo.toml | sed -n 2p | cut -d '"' -f 2) + echo "VERSION=$NEW_VERSION" >> $GITHUB_ENV + shell: /bin/bash -e {0} + + # Install the cross compilation toolchain + - name: Install Cross + id: install-cross + run: | + # Install cross + cargo install cross + # Clean the build artifacts + cargo clean --verbose + shell: /bin/bash -e {0} + + # Build the targets + - name: Build targets + id: build-targets + uses: actions-rs/cargo@v1 + with: + use-cross: true + command: build + args: --verbose --workspace --release --target ${{ matrix.target }} + + # Package the binary for each target + - name: Package the binary + id: package-binary + run: | + mkdir -p target/package + tar czf target/package/${{ matrix.target }}.tar.gz -C target/${{ matrix.target }}/release . + echo "${{ matrix.target }}.tar.gz=target/package/${{ matrix.target }}.tar.gz" >> $GITHUB_ENV + + # Upload the binary for each target + - name: Upload the binary + id: upload-binary + uses: actions/upload-artifact@v2 + with: + name: ${{ matrix.target }}.tar.gz + path: ${{ env[format('{0}.tar.gz', matrix.target)] }} + + # Release the binary to GitHub Releases + release: + name: โฏ Release ๐Ÿš€ + if: github.ref == 'refs/heads/main' && github.event_name == 'push' + needs: build + runs-on: ubuntu-latest + steps: + # Check out the repository code + - name: Checkout sources + uses: actions/checkout@v4 + + # Install the stable Rust toolchain + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + + # Update the version number based on the Cargo.toml file + - name: Update version number + run: | + NEW_VERSION=$(grep version Cargo.toml | sed -n 2p | cut -d '"' -f 2) + echo "VERSION=$NEW_VERSION" >> $GITHUB_ENV + shell: /bin/bash -e {0} + + # Cache dependencies to speed up subsequent builds + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: ~/.cargo + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo- + + # Download the artifacts from the build job + - name: Download artifacts + run: | + for target in x86_64-unknown-freebsd aarch64-unknown-linux-gnu aarch64-unknown-linux-musl arm-unknown-linux-gnueabi armv7-unknown-linux-gnueabihf i686-unknown-linux-gnu i686-unknown-linux-musl x86_64-unknown-linux-gnu x86_64-unknown-linux-musl aarch64-apple-darwin x86_64-apple-darwin x86_64-unknown-illumos; do + echo "Downloading $target artifact" + name="${target}.tar.gz" + echo "Artifact name: $name" + mkdir -p target/package + curl -sSL -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/vnd.github.v3+json" -L "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}/artifacts/{name}" -o "target/package/{name}" + done + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RUN_ID: ${{ github.event.workflow_run.id }} + + # Generate the changelog based on git log and template file + - name: Generate Changelog + run: | + # Append version information to CHANGELOG.md + echo "## Release v${{ env.VERSION }} - $(date +'%Y-%m-%d')" >> ${{ github.workspace }}/CHANGELOG.md + # Copy content of template file to CHANGELOG.md + cat TEMPLATE.md >> ${{ github.workspace }}/CHANGELOG.md + # Append git log to CHANGELOG.md + echo "$(git log --pretty=format:'%s' --reverse $(git describe --tags --abbrev=0)..HEAD)" >> ${{ github.workspace }}/CHANGELOG.md + # Append empty line to CHANGELOG.md + echo "" >> ${{ github.workspace }}/CHANGELOG.md + + # Append the artifact links to the changelog + - name: Append Artifact Links + run: | + echo "" >> ${{ github.workspace }}/CHANGELOG.md + echo "## Artifacts ๐ŸŽ" >> ${{ github.workspace }}/CHANGELOG.md + for filename in target/package/*.tar.gz; do + link="$(basename $filename)" + echo "* [$link](${{ github.server_url }}/${{ github.repository }}/releases/download/v${{ env.VERSION }}/$link)" >> ${{ github.workspace }}/CHANGELOG.md + done + + # Create the release on GitHub Releases + - name: Create Release + id: create-release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: v${{ env.VERSION }} + release_name: {name}} ๐Ÿฆ€ v${{ env.VERSION }} + body_path: ${{ github.workspace }}/CHANGELOG.md + draft: true + prerelease: false + + # Publish the release to Crates.io automatically + crate: + name: โฏ Crate.io ๐Ÿฆ€ + if: github.ref == 'refs/heads/main' && github.event_name == 'push' + needs: release + runs-on: ubuntu-latest + + steps: + # Check out the repository code + - name: Checkout + uses: actions/checkout@v4 + + # Install the stable Rust toolchain + - name: Install stable toolchain + id: install-toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + + # Cache dependencies to speed up subsequent builds + - name: Cache dependencies + id: cache-dependencies + uses: actions/cache@v2 + with: + path: /home/runner/.cargo/registry/index/ + key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo-index- + + # Update the version number based on the Cargo.toml file + - name: Update version number + id: update-version + run: | + NEW_VERSION=$(grep version Cargo.toml | sed -n 2p | cut -d '"' -f 2) + echo "VERSION=$NEW_VERSION" >> $GITHUB_ENV + shell: /bin/bash -e {0} + + # Publish the Rust library to Crate.io + - name: Publish Library to Crate.io + id: publish-library + uses: actions-rs/cargo@v1 + env: + CARGO_API_TOKEN: ${{ secrets.CARGO_API_TOKEN }} + with: + use-cross: true + command: publish + args: --dry-run --verbose --token "${CARGO_API_TOKEN}" diff --git a/template/criterion.tpl b/template/criterion.tpl index 2123c57..eeae715 100644 --- a/template/criterion.tpl +++ b/template/criterion.tpl @@ -1,52 +1,49 @@ -// Copyright notice and licensing information. -// These lines indicate the copyright of the software and its licensing terms. -// Copyright ยฉ 2024 {name}. All rights reserved. -// SPDX-License-Identifier: {license} +//! # Benchmark: libmake +//! +//! This benchmark tests the performance of the `libmake` crate using the Criterion library. +//! It measures the execution time of the `run` function from the `libmake` crate. +//! +//! ## Purpose +//! +//! The purpose of this benchmark is to assess the execution time of the `run` function +//! from the `{name}` crate under controlled conditions. It helps identify any potential +//! performance bottlenecks and allows for optimization if needed. +//! +//! ## Usage +//! +//! To run this benchmark, ensure that you have the `criterion` and `{name}` crates +//! included as dependencies in your project's `Cargo.toml` file. +//! +//! In your project's code, you can use the `criterion_group` and `criterion_main` macros +//! to define and run benchmarks. In this specific benchmark, the `{name}_benchmark` function +//! is defined to measure the execution time of the `run` function. +//! +//! ```rust +//! extern crate criterion; +//! extern crate {name}; +//! +//! use criterion::{criterion_group, criterion_main, Criterion}; +//! use {name}::run; +//! +//! fn {name}_benchmark(c: &mut Criterion) { +//! c.bench_function("{name}", |b| b.iter(run)); +//! } +//! +//! criterion_group!(benches, {name}_benchmark); +//! criterion_main!(benches); +//! ``` +//! +//! Running this benchmark will provide performance metrics for the `run` function +//! from the `{name}` crate, helping you evaluate and optimize its performance. -extern crate criterion; +#![allow(missing_docs)] use criterion::{criterion_group, criterion_main, Criterion}; -use {name}::{run, {name}_vec, {name}_map, {name}_join}; - -fn {name}_vec_benchmark(c: &mut Criterion) { - c.bench_function("{name}_vec_macro", |b| { - b.iter(|| { - {name}_vec![1, 2, 3, 4, 5] - }) - }); -} - -fn {name}_map_benchmark(c: &mut Criterion) { - c.bench_function("{name}_map_macro", |b| { - b.iter(|| { - {name}_map!["a" => 1, "b" => 2, "c" => 3, "d" => 4, "e" => 5] - }) - }); -} - -fn {name}_join_benchmark(c: &mut Criterion) { - c.bench_function("{name}_join_macro", |b| { - b.iter(|| { - {name}_join!["a", "b", "c", "d", "e"] - }) - }); -} +use {name}::run; fn {name}_benchmark(c: &mut Criterion) { - c.bench_function("{name}", |b| { - b.iter(|| { - for _ in 0..1000 { - run().unwrap(); - } - }) - }); + c.bench_function("{name}", |b| b.iter(run)); } -criterion_group!( - {name}_macros_benchmark, - {name}_vec_benchmark, - {name}_map_benchmark, - {name}_join_benchmark, - {name}_benchmark -); -criterion_main!({name}_macros_benchmark); +criterion_group!(benches, {name}_benchmark); +criterion_main!(benches); diff --git a/template/deepsource.tpl b/template/deepsource.tpl index 81145d5..e1aa2aa 100644 --- a/template/deepsource.tpl +++ b/template/deepsource.tpl @@ -4,5 +4,5 @@ version = 1 name = "rust" enabled = true - [analyzers.meta] - msrv = "stable" \ No newline at end of file +[analyzers.meta] +msrv = "stable" diff --git a/template/example.tpl b/template/example.tpl index cf74f49..abce4b9 100644 --- a/template/example.tpl +++ b/template/example.tpl @@ -1,3 +1,15 @@ -fn main() { +// Copyright notice and licensing information. +// These lines indicate the copyright of the software and its licensing terms. +// Copyright ยฉ 2024 {name}. All rights reserved. +// SPDX-License-Identifier: "MIT OR Apache-2.0" + + +//! This is an example of how to use the `{name}` crate. -} \ No newline at end of file +use {name}::{name}_print; + +fn main() { + {name}_print! { + "Hello, world!" + } +} diff --git a/template/lib.tpl b/template/lib.tpl index 4af36bf..80dc8d4 100644 --- a/template/lib.tpl +++ b/template/lib.tpl @@ -30,9 +30,9 @@ //! //! ```toml //! [dependencies] -//! {name} = "{version}" -//! serde = { version = "1.0", features = ["derive"] } -//! serde_json = "1.0" +//! {name} = {version} +//! serde = { version = "1.0.197", features = ["derive"] } +//! serde_json = "1.0.115" //! ``` //! //! ## Examples @@ -51,12 +51,6 @@ //! //! The project is licensed under the terms of the {license} license. //! -#![cfg_attr(feature = "bench", feature(test))] -#![deny(dead_code)] -#![deny(missing_debug_implementations)] -#![deny(missing_docs)] -#![forbid(unsafe_code)] -#![warn(unreachable_pub)] #![doc( html_favicon_url = "", html_logo_url = "", @@ -65,9 +59,6 @@ #![crate_name = "{name}"] #![crate_type = "lib"] -/// The `loggers` module contains the loggers for the library. -pub mod loggers; - /// The `macros` module contains functions for generating macros. pub mod macros; @@ -88,12 +79,12 @@ use std::error::Error; )] #[allow(non_camel_case_types)] -/// {name} is a data structure that ... +/// `{name}` is a data structure that ... pub struct {name} { // Add any data fields needed here } -/// This is the main entry point for the {name} library. +/// This is the main entry point for the `{name}` library. pub fn run() -> Result<(), Box> { // Add your code here let name = "{name}"; @@ -103,7 +94,7 @@ pub fn run() -> Result<(), Box> { impl {name} { - /// Creates a new instance of {name} + /// Creates a new instance of `{name}` pub fn new() -> Self { Self { // Initialize any data fields here @@ -112,7 +103,7 @@ impl {name} { } impl Default for {name} { - /// Creates a new instance of {name} with default values + /// Creates a new instance of `{name}` with default values fn default() -> Self { Self::new() } diff --git a/template/loggers.tpl b/template/loggers.tpl deleted file mode 100644 index 7f9301b..0000000 --- a/template/loggers.tpl +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright notice and licensing information. -// These lines indicate the copyright of the software and its licensing terms. -// Copyright ยฉ 2024 {name}. All rights reserved. -// SPDX-License-Identifier: {license} - -//! Application logging functionality -//! -//! Provides access to logging functions and types. -//! -use env_logger::Env; -use rlg::LogLevel; -use std::io::Write; - -/// Initializes the logging system. -/// -/// This function sets up the logging system using the `env_logger` crate. It takes a `default_log_level` parameter, which determines the minimum log level to be displayed. The function returns a `Result` type, which will be `Ok` if the logging system is initialized successfully, or an error if there was a problem. -/// -/// # Examples -/// -/// ``` -/// use rlg::LogLevel; -/// use {name}::loggers::init_logger; -/// -/// // Initialize the logging system with a default log level of `info` -/// init_logger(Some(LogLevel::INFO)).unwrap(); -/// ``` -pub fn init_logger( - default_log_level: Option, -) -> Result<(), Box> { - let env = Env::default().default_filter_or( - default_log_level.unwrap_or(LogLevel::INFO).to_string(), - ); - - env_logger::Builder::from_env(env) - .format(|buf, record| { - writeln!(buf, "[{}] - {}", record.level(), record.args()) - }) - .init(); - - Ok(()) -} diff --git a/template/main.tpl b/template/main.tpl index 435fb7d..57ea6d9 100644 --- a/template/main.tpl +++ b/template/main.tpl @@ -3,7 +3,9 @@ // Copyright ยฉ 2024 {name}. All rights reserved. // SPDX-License-Identifier: {license} -/// This is the main entry point for the {name} application. +//! This crate contains the main entry point for the `{name}` application. + +/// This is the main entry point for the `{name}` application. fn main() { // Call the `run()` function from the `{name}` module. if let Err(err) = {name}::run() { diff --git a/template/test_loggers.tpl b/template/test_loggers.tpl deleted file mode 100644 index a44e9d8..0000000 --- a/template/test_loggers.tpl +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright notice and licensing information. -// These lines indicate the copyright of the software and its licensing terms. -// Copyright ยฉ 2024 {name}. All rights reserved. -// SPDX-License-Identifier: {license} - -#[cfg(test)] -mod tests { - - use rlg::macro_log; - use rlg::{LogFormat, LogLevel}; - - #[test] - fn test_logging() { - // Create a log entry - let log_entry = - macro_log!( - "session_id", - "time", - &LogLevel::INFO, - "component", - "Log message", - &LogFormat::CLF - ); - - // Define expected values - let expected_session_id = "session_id"; - let expected_time = "time"; - let expected_level = LogLevel::INFO; - let expected_component = "component"; - let expected_description = "Log message"; - let expected_format = LogFormat::CLF; - - // Assert that individual fields match the expected values - assert_eq!(log_entry.session_id, expected_session_id); - assert_eq!(log_entry.time, expected_time); - assert_eq!(log_entry.level, expected_level); - assert_eq!(log_entry.component, expected_component); - assert_eq!(log_entry.description, expected_description); - assert_eq!(log_entry.format, expected_format); - } -} diff --git a/tests/data/mylibrary.csv b/tests/data/mylibrary.csv index eaf2260..05e5421 100644 --- a/tests/data/mylibrary.csv +++ b/tests/data/mylibrary.csv @@ -1,2 +1,2 @@ author,build,categories,description,documentation,edition,email,homepage,keywords,license,name,output,readme,repository,rustversion,version,website -Me,build.rs,"['category 1', 'category 2']",A library for doing things,https://lib.rs/crates/my_library,2021,test@test.com,https://test.com,"['keyword1', 'keyword2']",MIT OR Apache-2.0,my_library,my_library,README.md,https://github.com/test/test,1.75.0,0.2.2,https://test.com +Me,build.rs,"['category 1', 'category 2']",A library for doing things,https://lib.rs/crates/my_library,2021,test@test.com,https://test.com,"['keyword1', 'keyword2']",MIT OR Apache-2.0,my_library,my_library,README.md,https://github.com/test/test,1.75.0,0.2.3,https://test.com diff --git a/tests/data/mylibrary.ini b/tests/data/mylibrary.ini index 1c1b568..3ca4334 100644 --- a/tests/data/mylibrary.ini +++ b/tests/data/mylibrary.ini @@ -1,17 +1,17 @@ author = "Me" build = "build.rs" -categories = "'category 1','category 2','category 3'" +categories = ["category 1","category 2","category 3"] description = "A library for doing things" documentation = "https://lib.rs/crates/my_library" edition = "2021" email = "test@test.com" homepage = "https://test.com" -keywords = "'keyword 1','keyword 2','keyword 3'" +keywords = ['keyword 1','keyword 2','keyword 3'] license = "MIT OR Apache-2.0" name = "my_library" output = "my_library" readme = "README.md" repository = "https://github.com/test/test" rustversion = "1.75.0" -version = "0.2.2" +version = "0.2.3" website = "https://test.com" diff --git a/tests/data/mylibrary.json b/tests/data/mylibrary.json index 41f29db..e02c334 100644 --- a/tests/data/mylibrary.json +++ b/tests/data/mylibrary.json @@ -14,6 +14,6 @@ "readme": "README.md", "repository": "https://github.com/test/test", "rustversion": "1.75.0", - "version": "0.2.2", + "version": "0.2.3", "website": "https://test.com" } diff --git a/tests/data/mylibrary.toml b/tests/data/mylibrary.toml index 1c1b568..4afd7b7 100644 --- a/tests/data/mylibrary.toml +++ b/tests/data/mylibrary.toml @@ -13,5 +13,5 @@ output = "my_library" readme = "README.md" repository = "https://github.com/test/test" rustversion = "1.75.0" -version = "0.2.2" +version = "0.2.3" website = "https://test.com" diff --git a/tests/data/mylibrary.yaml b/tests/data/mylibrary.yaml index 8072147..b4a49d3 100644 --- a/tests/data/mylibrary.yaml +++ b/tests/data/mylibrary.yaml @@ -13,5 +13,5 @@ output: my_library readme: README.md repository: https://github.com/test/test rustversion: '1.75.0' -version: '0.2.2' +version: '0.2.3' website: https://test.com diff --git a/tests/test_args.rs b/tests/test_args.rs index ca52ce8..fad405a 100644 --- a/tests/test_args.rs +++ b/tests/test_args.rs @@ -1,8 +1,7 @@ use clap::{Arg, Command}; -use libmake::args::extract_manual_params; use libmake::{ - args::{process_arguments, validate_params}, - generator::FileGenerationParams, + args::{extract_manual_params, process_arguments, validate_params}, + models::model_params::FileGenerationParams, }; // Tests the process_arguments function with valid arguments @@ -89,7 +88,7 @@ fn test_validate_params_invalid_edition() { assert!(result.is_err()); assert_eq!( result.unwrap_err().to_string(), - "Invalid edition: 2023. Supported editions are 2015, 2018, and 2021.".to_string() + "Invalid edition: 2023. Supported editions are: 2015, 2018, 2021.".to_string() ); } @@ -149,7 +148,7 @@ fn test_validate_params_invalid_email() { assert!(result.is_err()); assert_eq!( result.unwrap_err().to_string(), - "Invalid email address: . Email address should contain '@'.".to_string() + "Invalid email address: .".to_string() ); } @@ -209,7 +208,7 @@ fn test_validate_params_invalid_repository() { assert!(result.is_err()); assert_eq!( result.unwrap_err().to_string(), - "Invalid repository URL: 123. Repository URL should start with 'https://' or 'git://'.".to_string() + "Invalid repository URL: 123. Repository URL should be a valid Git URL.".to_string() ); } @@ -241,7 +240,7 @@ fn test_validate_params_invalid_rustversion() { assert!(result.is_err()); assert_eq!( result.unwrap_err().to_string(), - "Invalid Rust version: 2.0. Rust version should start with '1.'.".to_string() + "Invalid Rust version: 2.0. Rust version should be in the format '1.x.y'.".to_string() ); } @@ -428,7 +427,7 @@ fn test_extract_manual_params_all_fields() { .long("repository") .value_name("REPOSITORY") .default_value( - "https://github.com/test/test_lib", + "https://github.com/test/test_lib.git", ), ) .arg( @@ -480,7 +479,7 @@ fn test_extract_manual_params_all_fields() { "--readme", "README.md", "--repository", - "https://github.com/test/test_lib", + "https://github.com/test/test_lib.git", "--rustversion", "1.60.0", "--version", @@ -490,7 +489,7 @@ fn test_extract_manual_params_all_fields() { ]); let result = extract_manual_params( - matches.subcommand_matches("manual").unwrap() + matches.subcommand_matches("manual").unwrap(), ); assert!(result.is_ok()); @@ -519,7 +518,7 @@ fn test_extract_manual_params_all_fields() { assert_eq!(params.readme, Some("README.md".to_string())); assert_eq!( params.repository, - Some("https://github.com/test/test_lib".to_string()) + Some("https://github.com/test/test_lib.git".to_string()) ); assert_eq!(params.rustversion, Some("1.60.0".to_string())); assert_eq!(params.version, Some("0.1.0".to_string())); diff --git a/tests/test_ascii.rs b/tests/test_ascii.rs index fad81ff..75a4d55 100644 --- a/tests/test_ascii.rs +++ b/tests/test_ascii.rs @@ -1,6 +1,10 @@ #[cfg(test)] mod tests { - use libmake::ascii::{generate_ascii_art, load_standard_font, ArtError}; + use libmake::{ + generators::ascii::{generate_ascii_art, load_standard_font}, + macro_ascii, + models::error_ascii_art::AsciiArtError + }; #[test] fn test_generate_ascii_art_success() { @@ -16,7 +20,7 @@ mod tests { let text = ""; let result = generate_ascii_art(text); assert!(result.is_err()); - assert!(matches!(result.unwrap_err(), ArtError::ConversionError)); + assert!(matches!(result.unwrap_err(), AsciiArtError::ConversionError)); } #[test] @@ -30,6 +34,54 @@ mod tests { let text = "\u{1F600}"; // Emoji character let result = generate_ascii_art(text); assert!(result.is_err()); - assert!(matches!(result.unwrap_err(), ArtError::ConversionError)); + assert!(matches!(result.unwrap_err(), AsciiArtError::ConversionError)); + } + + #[test] + fn test_generate_ascii_art_multiple_lines() { + let text = "Hello,\nworld!"; + let result = generate_ascii_art(text); + assert!(result.is_ok()); + let ascii_art = result.unwrap(); + assert!(ascii_art.contains('\n')); + } + + #[test] + fn test_generate_ascii_art_special_characters() { + let text = "!@#$%^&*()_+"; + let result = generate_ascii_art(text); + assert!(result.is_ok()); + let ascii_art = result.unwrap(); + assert!(!ascii_art.is_empty()); + } + + #[test] + fn test_macro_ascii_success() { + let ascii_art = macro_ascii!("Hello, world!"); + assert!(!ascii_art.is_empty()); + } + + #[test] + #[should_panic(expected = "Failed to generate ASCII art: Failed to convert text to ASCII art")] + fn test_macro_ascii_empty_text() { + let _ = macro_ascii!(""); + } + + #[test] + #[should_panic(expected = "Failed to generate ASCII art: Failed to convert text to ASCII art")] + fn test_macro_ascii_conversion_error() { + let _ = macro_ascii!("\u{1F600}"); // Emoji character + } + + #[test] + fn test_macro_ascii_multiple_lines() { + let ascii_art = macro_ascii!("Hello,\nworld!"); + assert!(ascii_art.contains('\n')); + } + + #[test] + fn test_macro_ascii_special_characters() { + let ascii_art = macro_ascii!("!@#$%^&*()_+"); + assert!(!ascii_art.is_empty()); } } diff --git a/tests/test_generator.rs b/tests/test_generator.rs index 8ad4345..e13015d 100644 --- a/tests/test_generator.rs +++ b/tests/test_generator.rs @@ -1,12 +1,11 @@ -use libmake::generator::{ - create_directory, generate_files, generate_from_args, -}; use libmake::{ - assert_generate_files, - generator::{ - generate_from_config, generate_from_yaml, FileGenerationParams, + generator::generate_from_config, + generators::{args::generate_from_args, yaml::generate_from_yaml}, + macro_generate_files, + models::model_params::FileGenerationParams, + utils::{ + create_directory, get_csv_field, get_json_field, get_yaml_field, }, - utils::{get_csv_field, get_json_field, get_yaml_field}, }; use tempfile::tempdir; @@ -32,9 +31,9 @@ fn test_get_json_field() { let value = if Path::new(file_path).exists() { get_json_field(Some(file_path), field_name) } else { - Ok(String::new()) // Wrap the String in Ok + Ok(String::new()) }; - assert_eq!(value.unwrap(), "null".to_string()); // Unwrap the value and compare with "null" + assert_eq!(value.unwrap_or_default(), "".to_string()); } /// Tests the `get_yaml_field` function by passing a YAML file path and @@ -46,9 +45,9 @@ fn test_get_yaml_field() { let value = if Path::new(file_path).exists() { get_yaml_field(Some(file_path), field_name) } else { - Ok(String::new()) // Wrapping the String in Ok to match the expected type + Ok(String::new()) }; - assert_eq!(value.unwrap(), "null".to_string()); // Unwrap the value and compare with "null" + assert_eq!(value.unwrap_or_default(), "".to_string()); } /// Tests the `generate_from_config` function by passing a YAML file @@ -146,7 +145,7 @@ fn test_from_args() { /// `FileGenerationParams` struct and checking if the function runs /// without errors. #[test] -fn test_assert_generate_files() { +fn test_macro_generate_files() { let temp_dir = env::temp_dir().join("my_library"); let mut params = FileGenerationParams::new(); params.output = @@ -155,7 +154,7 @@ fn test_assert_generate_files() { #[test] #[allow(clippy::redundant_clone)] -fn test_generate_files() { +fn test_generate_files() -> Result<(), String> { // Create a temporary directory let temp_directory = tempdir(); let temp_path = temp_directory.unwrap().path().to_owned(); @@ -165,13 +164,15 @@ fn test_generate_files() { params.output = Some(temp_path.to_str().unwrap().to_owned()); // Call the function you want to test - assert_generate_files!(params.clone()); + macro_generate_files!(params.clone())?; // Assert that the temporary directory exists assert!(temp_path.exists()); // Clean up: Remove the temporary directory and its contents std::fs::remove_dir_all(temp_path).unwrap(); + + Ok(()) } /// Tests the `create_directory` function by passing an invalid path and diff --git a/tests/test_loggers.rs b/tests/test_loggers.rs deleted file mode 100644 index 58fa5cf..0000000 --- a/tests/test_loggers.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright notice and licensing information. -// These lines indicate the copyright of the software and its licensing terms. -// SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. -// Copyright ยฉ 2024 LibMake. All rights reserved. - -#[cfg(test)] -mod tests { - - use rlg::{log_format::LogFormat, log_level::LogLevel, macro_log}; - - #[test] - fn test_logging() { - // Create a log entry - let log_entry = macro_log!( - "session_id", - "time", - &LogLevel::INFO, - "component", - "Log message", - &LogFormat::CLF - ); - - // Define expected values - let expected_session_id = "session_id"; - let expected_time = "time"; - let expected_level = LogLevel::INFO; - let expected_component = "component"; - let expected_description = "Log message"; - let expected_format = LogFormat::CLF; - - // Assert that individual fields match the expected values - assert_eq!(log_entry.session_id, expected_session_id); - assert_eq!(log_entry.time, expected_time); - assert_eq!(log_entry.level, expected_level); - assert_eq!(log_entry.component, expected_component); - assert_eq!(log_entry.description, expected_description); - assert_eq!(log_entry.format, expected_format); - } -} diff --git a/tests/test_macros.rs b/tests/test_macros.rs index 6b6df8c..bbf934a 100644 --- a/tests/test_macros.rs +++ b/tests/test_macros.rs @@ -1,79 +1,91 @@ #[cfg(test)] mod tests { - use libmake::generator::{ - generate_files, generate_from_csv, generate_from_json, - generate_from_yaml, - }; - use libmake::generator::{ - generate_from_config, FileGenerationParams, - }; + use libmake::models::model_params::FileGenerationParams; use std::path::Path; + use libmake::macro_create_directories; + use libmake::{ - assert_create_directory, assert_generate_files, - assert_generate_from_config, assert_generate_from_csv, - assert_generate_from_json, assert_generate_from_yaml, + macro_generate_files, macro_generate_from_config, + macro_generate_from_csv, macro_generate_from_json, + macro_generate_from_yaml, }; // Unit test for the `create_directory()` function. #[test] fn test_create_directory() { - assert_create_directory!("my_library"); + let result = macro_create_directories!("my_library"); + match result { + Ok(()) => println!("Directory created successfully!"), + Err(err) => println!("Error creating directory: {}", err), + } } // Unit test for the `generate_files()` function. #[test] #[allow(clippy::redundant_clone)] - fn test_generate_files() { + fn test_generate_files() -> Result<(), String> { let mut params = FileGenerationParams::new(); params.output = Some("my_library".into()); - assert_generate_files!(params.clone()); + macro_generate_files!(params.clone())?; + Ok(()) } // Unit test for the `generate_from_csv()` function. #[test] - fn test_generate_from_csv() { - assert_generate_from_csv!("./tests/data/mylibrary.csv"); + fn test_generate_from_csv() -> Result<(), String> { + macro_generate_from_csv!("./tests/data/mylibrary.csv")?; + Ok(()) } // Unit test for the `generate_from_json()` function. #[test] - fn test_generate_from_json() { - assert_generate_from_json!("./tests/data/mylibrary.json"); + fn test_generate_from_json() -> Result<(), String> { + macro_generate_from_json!("./tests/data/mylibrary.json")?; + Ok(()) } // Unit test for the `generate_from_yaml()` function. #[test] - fn test_generate_from_yaml() { - assert_generate_from_yaml!("./tests/data/mylibrary.yaml"); + fn test_generate_from_yaml() -> Result<(), String> { + macro_generate_from_yaml!("./tests/data/mylibrary.yaml")?; + Ok(()) } // Unit test for the `generate_from_config()` function. #[test] - fn test_generate_from_config() { - assert_generate_from_config!( + fn test_generate_from_config() -> Result<(), String> { + macro_generate_from_config!( "./tests/data/mylibrary.yaml", "yaml" - ); + )?; + Ok(()) } - // Unit test for the `assert_create_directory!()` macro. + // Unit test for the `macro_create_directories!()` macro. #[test] - fn test_assert_create_directory() { - assert_create_directory!("./target/tmp"); + fn test_macro_create_directories() { + let result = macro_create_directories!("./target/tmp"); + match result { + Ok(()) => println!("Directory created successfully!"), + Err(err) => println!("Error creating directory: {}", err), + } let _ = std::fs::remove_dir_all("./target/tmp"); } - // Unit test for the `assert_generate_from_csv!()` macro. + // Unit test for the `macro_generate_from_csv!()` macro. #[test] - fn test_assert_generate_from_csv() { - assert_generate_from_csv!("./tests/data/mylibrary.csv"); + fn test_macro_generate_from_csv() -> Result<(), String> { + macro_generate_from_csv!("./tests/data/mylibrary.csv")?; assert!(Path::new("my_library").exists()); + Ok(()) } - // Unit test for the `assert_generate_from_json!()` macro. + // Unit test for the `macro_generate_from_json!()` macro. #[test] - fn test_assert_generate_from_json() { - assert_generate_from_json!("./tests/data/mylibrary.json"); + fn test_macro_generate_from_json() -> Result<(), String> { + macro_generate_from_json!("./tests/data/mylibrary.json")?; assert!(Path::new("my_library").exists()); + Ok(()) } - // Unit test for the `assert_generate_from_yaml!()` macro. + // Unit test for the `macro_generate_from_yaml!()` macro. #[test] - fn test_assert_generate_from_yaml() { - assert_generate_from_yaml!("./tests/data/mylibrary.yaml"); + fn test_macro_generate_from_yaml() -> Result<(), String> { + macro_generate_from_yaml!("./tests/data/mylibrary.yaml")?; assert!(Path::new("my_library").exists()); + Ok(()) } } diff --git a/tests/test_utils.rs b/tests/test_utils.rs index 0c4a86c..9b85b4c 100644 --- a/tests/test_utils.rs +++ b/tests/test_utils.rs @@ -91,7 +91,7 @@ mod tests { ); assert_eq!( get_csv_field(Some(file_path), 15), - Some(vec!["0.2.2".to_string()]) + Some(vec!["0.2.3".to_string()]) ); assert_eq!( get_csv_field(Some(file_path), 16), @@ -159,6 +159,6 @@ mod tests { get_config_field(file_path, Some("unknown"), field_name) .map_err(|err| err.to_string()) .unwrap_err(); - assert_eq!(actual_unknown_format_value, "Unsupported file format: unknown. Supported formats are 'json' and 'yaml'."); + assert_eq!(actual_unknown_format_value, "Unsupported file format: unknown. Supported formats are 'json', 'yaml', and 'ini'."); } }