├── .deepsource.toml ├── .editorconfig ├── .github ├── CODE-OF-CONDUCT.md ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── SECURITY.md ├── dependabot.yml ├── funding.yml └── workflows │ ├── audit.yml │ ├── check.yml │ ├── coverage.yml │ ├── document.yml │ ├── lint.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── TEMPLATE.md ├── benches └── criterion.rs ├── build.rs ├── deny.toml ├── examples ├── example.rs ├── generate_from_args.rs ├── generate_from_config.rs ├── generate_from_csv.rs ├── generate_from_json.rs ├── generate_from_toml.rs ├── generate_from_yaml.rs ├── get_csv_field.rs ├── get_json_field.rs └── get_yaml_field.rs ├── rustfmt.toml ├── src ├── args.rs ├── cli.rs ├── generator.rs ├── generators │ ├── args.rs │ ├── ascii.rs │ ├── csv.rs │ ├── ini.rs │ ├── json.rs │ ├── mod.rs │ ├── toml.rs │ └── yaml.rs ├── interface.rs ├── lib.rs ├── macros │ ├── ascii_macros.rs │ ├── directory_macros.rs │ ├── file_macros.rs │ ├── generator_macros.rs │ ├── log_macros.rs │ ├── mod.rs │ └── utility_macros.rs ├── main.rs ├── models │ ├── error_ascii_art.rs │ ├── mod.rs │ └── model_params.rs ├── utilities │ ├── directory.rs │ ├── mod.rs │ └── uuid.rs └── utils.rs ├── template ├── AUTHORS.tpl ├── CONTRIBUTING.tpl ├── Cargo.tpl ├── README.tpl ├── TEMPLATE.tpl ├── build.tpl ├── ci.tpl ├── criterion.tpl ├── deepsource.tpl ├── deny.tpl ├── example.tpl ├── github │ └── workflows │ │ ├── audit.tpl │ │ ├── check.tpl │ │ ├── coverage.tpl │ │ ├── document.tpl │ │ ├── lint.tpl │ │ ├── release.tpl │ │ └── test.tpl ├── gitignore.tpl ├── lib.tpl ├── macros.tpl ├── main.tpl ├── rustfmt.tpl ├── test.tpl └── test_test.tpl └── tests ├── data ├── mylibrary.csv ├── mylibrary.ini ├── mylibrary.json ├── mylibrary.toml └── mylibrary.yaml ├── generators ├── mod.rs ├── test_args.rs ├── test_ascii.rs ├── test_csv.rs ├── test_ini.rs ├── test_json.rs ├── test_toml.rs └── test_yaml.rs ├── macros ├── mod.rs ├── test_ascii_macros.rs ├── test_directory_macros.rs ├── test_file_macros.rs ├── test_generator_macros.rs ├── test_log_macros.rs └── test_utility_macros.rs ├── mod.rs ├── models ├── mod.rs ├── test_error_ascii_art.rs └── test_model_params.rs ├── test_cli.rs ├── test_generator.rs ├── test_interface.rs ├── test_utils.rs └── utilities ├── mod.rs ├── test_directory.rs └── test_uuid.rs /.deepsource.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[analyzers]] 4 | name = "rust" 5 | enabled = true 6 | 7 | [analyzers.meta] 8 | msrv = "stable" 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Copyright © 2023 LibMake. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | # EditorConfig helps developers define and maintain consistent 5 | # coding styles between different editors and IDEs 6 | # editorconfig.org 7 | 8 | root = true 9 | 10 | [*] 11 | end_of_line = lf 12 | charset = utf-8 13 | trim_trailing_whitespace = true 14 | insert_final_newline = true 15 | indent_style = space 16 | indent_size = 4 17 | 18 | [*.rs] 19 | max_line_length = 80 20 | 21 | [*.md] 22 | # double whitespace at end of line 23 | # denotes a line break in Markdown 24 | trim_trailing_whitespace = false 25 | 26 | [*.yml] 27 | indent_size = 2 28 | 29 | [Makefile] 30 | indent_style = tab 31 | -------------------------------------------------------------------------------- /.github/CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our 7 | project and our community a harassment-free experience for everyone, 8 | regardless of age, body size, disability, ethnicity, gender identity and 9 | expression, level of experience, nationality, personal appearance, race, 10 | religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behaviour that contributes to creating a positive 15 | environment include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behaviour by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual 26 | attention or advances 27 | - Trolling, insulting/derogatory comments, and personal or political 28 | attacks 29 | - Public or private harassment 30 | - Publishing others' private information, such as a physical or 31 | electronic address, without explicit permission 32 | - Other conduct which could reasonably be considered inappropriate in a 33 | professional setting 34 | 35 | ## Our Responsibilities 36 | 37 | Project maintainers are responsible for clarifying the standards of 38 | acceptable behaviour and are expected to take appropriate and fair 39 | corrective action in response to any instances of unacceptable 40 | behaviour. 41 | 42 | Project maintainers have the right and responsibility to remove, edit, 43 | or reject comments, commits, code, wiki edits, issues, and other 44 | contributions that are not aligned to this Code of Conduct, or to ban 45 | temporarily or permanently any contributor for other behaviors that they 46 | deem inappropriate, threatening, offensive, or harmful. 47 | 48 | ## Scope 49 | 50 | This Code of Conduct applies both within project spaces and in public 51 | spaces when an individual is representing the project or its community. 52 | Examples of representing a project or community include using an 53 | official project e-mail address, posting via an official social media 54 | account, or acting as an appointed representative at an online or 55 | offline event. Representation of a project may be further defined and 56 | clarified by project maintainers. 57 | 58 | ## Enforcement 59 | 60 | Instances of abusive, harassing, or otherwise unacceptable behaviour may 61 | be reported by contacting the project team. The project team will review 62 | and investigate all complaints, and will respond in a way that it deems 63 | appropriate to the circumstances. The project team is obligated to 64 | maintain confidentiality with regard to the reporter of an incident. 65 | Further details of specific enforcement policies may be posted 66 | separately. 67 | 68 | Project maintainers who do not follow or enforce the Code of Conduct in 69 | good faith may face temporary or permanent repercussions as determined 70 | by other members of the project's leadership. 71 | 72 | ## Attribution 73 | 74 | This Code of Conduct is adapted from the Contributor Covenant homepage, 75 | version 1.4, available at 76 | [version](http://contributor-covenant.org/version/1/4) 77 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | @sebastienrousseau/libmake -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Create a report to help us improve 3 | labels: ["bug-report"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: Thanks for filing a 🐛 bug report 😄! 8 | - type: textarea 9 | id: problem 10 | attributes: 11 | label: Problem 12 | description: > 13 | Please provide a clear and concise description of what the bug is, 14 | including what currently happens and what you expected to happen. 15 | validations: 16 | required: true 17 | - type: textarea 18 | id: steps 19 | attributes: 20 | label: Steps 21 | description: Please list the steps to reproduce the bug. 22 | placeholder: | 23 | 1. 24 | 2. 25 | 3. 26 | - type: textarea 27 | id: possible-solutions 28 | attributes: 29 | label: Possible Solution(s) 30 | description: > 31 | Not obligatory, but suggest a fix/reason for the bug, 32 | or ideas how to implement the addition or change. 33 | - type: textarea 34 | id: notes 35 | attributes: 36 | label: Notes 37 | description: Provide any additional notes that might be helpful. 38 | - type: textarea 39 | id: version 40 | attributes: 41 | label: Version 42 | description: Please paste the output of running `cargo version --verbose`. 43 | render: text -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | contact_links: 2 | - name: Question 3 | url: https://users.rust-lang.org 4 | about: > 5 | Got a question about Cargo? Ask the community on the user forum. 6 | - name: Inspiring Idea 7 | url: https://internals.rust-lang.org/c/tools-and-infrastructure/cargo 8 | about: > 9 | Need more discussions with your next big idea? 10 | Reach out the coummunity on the internals forum. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Suggest an idea for enhancement 3 | labels: ["feature-request"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thanks for filing a feature request! 9 | 10 | If the feature request is relatively small and already with a possible solution, this might be the place for you. 11 | 12 | If you are brewing a big feature that needs feedback from the community, [the internal forum] is the best fit, especially for pre-RFC. You can also talk the idea over with other developers in [#t-cargo Zulip stream]. 13 | 14 | [the internal forum]: https://internals.rust-lang.org/c/tools-and-infrastructure/cargo/15 15 | [#t-cargo Zulip stream]: https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo 16 | - type: textarea 17 | id: problem 18 | attributes: 19 | label: Problem 20 | description: > 21 | Please provide a clear description of your use case and the problem 22 | this feature request is trying to solve. 23 | validations: 24 | required: true 25 | - type: textarea 26 | id: solution 27 | attributes: 28 | label: Proposed Solution 29 | description: > 30 | Please provide a clear and concise description of what you want to happen. 31 | - type: textarea 32 | id: notes 33 | attributes: 34 | label: Notes 35 | description: Provide any additional context or information that might be helpful. -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | We take the security of our software products and services seriously, 4 | which includes all source code repositories managed through our GitHub 5 | repositories. 6 | 7 | If you believe you have found a security vulnerability in any of our 8 | repository, please report it to us as described below. 9 | 10 | ## Reporting Security Issues 11 | 12 | Please include the requested information listed below (as much as you 13 | can provide) to help us better understand the nature and scope of the 14 | possible issue: 15 | 16 | - Type of issue (e.g. buffer overflow, SQL injection, cross-site 17 | scripting, etc.) 18 | - Full paths of source file(s) related to the manifestation of the issue 19 | - The location of the affected source code (tag/branch/commit or direct 20 | URL) 21 | - Any special configuration required to reproduce the issue 22 | - Step-by-step instructions to reproduce the issue 23 | - Proof-of-concept or exploit code (if possible) 24 | - Impact of the issue, including how an attacker might exploit the issue 25 | 26 | This information will help us triage your report more quickly. 27 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "cargo" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /.github/funding.yml: -------------------------------------------------------------------------------- 1 | github: sebastienrousseau 2 | custom: https://paypal.me/wwdseb 3 | -------------------------------------------------------------------------------- /.github/workflows/audit.yml: -------------------------------------------------------------------------------- 1 | name: 🧪 Audit 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - feat/libmake 8 | pull_request: 9 | branches: 10 | - feat/libmake 11 | release: 12 | types: [created] 13 | 14 | jobs: 15 | dependencies: 16 | name: Audit dependencies 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: hecrj/setup-rust-action@v2 20 | - name: Install cargo-audit 21 | run: cargo install cargo-audit 22 | 23 | - uses: actions/checkout@v4 24 | - name: Resolve dependencies 25 | run: cargo update 26 | 27 | - name: Audit vulnerabilities 28 | run: cargo audit 29 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: 🧪 Check 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - feat/libmake 8 | pull_request: 9 | branches: 10 | - feat/libmake 11 | release: 12 | types: [created] 13 | 14 | jobs: 15 | all: 16 | name: Check 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: hecrj/setup-rust-action@v2 20 | with: 21 | components: clippy 22 | - uses: actions/checkout@v4 23 | - name: Check lints 24 | run: cargo check --all-targets --workspace --all-features 25 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: 📶 Coverage 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | coverage: 14 | name: Code Coverage 15 | runs-on: ubuntu-latest 16 | env: 17 | CARGO_INCREMENTAL: "0" 18 | RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests" 19 | RUSTDOCFLAGS: "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests" 20 | 21 | steps: 22 | # Checkout the repository 23 | - name: Checkout repository 24 | uses: actions/checkout@v4 25 | 26 | # Setup Rust nightly 27 | - name: Install Rust 28 | uses: actions-rs/toolchain@v1 29 | id: toolchain 30 | with: 31 | toolchain: nightly 32 | override: true 33 | 34 | # Configure cache for Cargo 35 | - name: Cache Cargo registry, index 36 | uses: actions/cache@v4 37 | id: cache-cargo 38 | with: 39 | path: | 40 | ~/.cargo/registry 41 | ~/.cargo/bin 42 | ~/.cargo/git 43 | key: linux-${{ steps.toolchain.outputs.rustc_hash }}-rust-cov-${{ hashFiles('**/Cargo.lock') }} 44 | 45 | # Run tests with all features 46 | - name: Test (cargo test) 47 | uses: actions-rs/cargo@v1 48 | with: 49 | command: test 50 | args: "--workspace" 51 | 52 | # Install grcov 53 | - uses: actions-rs/grcov@v0.1 54 | id: coverage 55 | 56 | # Upload to Codecov.io 57 | - name: Upload to Codecov.io 58 | uses: codecov/codecov-action@v4 59 | with: 60 | token: ${{ secrets.CODECOV_TOKEN }} 61 | file: ${{ steps.coverage.outputs.report }} 62 | -------------------------------------------------------------------------------- /.github/workflows/document.yml: -------------------------------------------------------------------------------- 1 | name: 🧪 Document 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | release: 11 | types: [created] 12 | 13 | jobs: 14 | all: 15 | name: Document 16 | if: github.ref == 'refs/heads/main' && github.event_name == 'push' 17 | runs-on: ubuntu-latest 18 | concurrency: 19 | group: ${{ github.workflow }}-${{ github.ref }} 20 | steps: 21 | - uses: hecrj/setup-rust-action@v2 22 | with: 23 | rust-version: nightly 24 | 25 | - uses: actions/checkout@v4 26 | 27 | - name: Update libssl 28 | run: | 29 | sudo apt-get update 30 | sudo apt-get install -y libssl1.1 31 | 32 | - name: Generate documentation for all features and publish it 33 | run: | 34 | RUSTDOCFLAGS="--cfg docsrs" \ 35 | cargo doc --no-deps --all-features --workspace 36 | # Write index.html with redirect 37 | echo '' > ./target/doc/index.html 38 | 39 | - name: Deploy 40 | uses: actions/upload-artifact@v4 41 | with: 42 | name: documentation 43 | path: target/doc 44 | if-no-files-found: error 45 | retention-days: 1 46 | 47 | - name: Write CNAME file 48 | run: echo 'doc.libmake.com' > ./target/doc/CNAME 49 | 50 | - name: Deploy to GitHub Pages 51 | uses: peaceiris/actions-gh-pages@v4 52 | with: 53 | cname: true 54 | commit_message: Deploy documentation at ${{ github.sha }} 55 | github_token: ${{ secrets.GITHUB_TOKEN }} 56 | publish_branch: gh-pages 57 | publish_dir: ./target/doc 58 | user_email: actions@users.noreply.github.com 59 | user_name: github-actions 60 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: 🧪 Document 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | release: 11 | types: [created] 12 | 13 | jobs: 14 | all: 15 | name: Document 16 | if: github.ref == 'refs/heads/main' && github.event_name == 'push' 17 | runs-on: ubuntu-latest 18 | concurrency: 19 | group: ${{ github.workflow }}-${{ github.ref }} 20 | steps: 21 | - uses: hecrj/setup-rust-action@v2 22 | with: 23 | rust-version: nightly 24 | 25 | - uses: actions/checkout@v4 26 | 27 | - name: Update libssl 28 | run: | 29 | sudo apt-get update 30 | sudo apt-get install -y libssl1.1 31 | 32 | - name: Generate documentation for all features and publish it 33 | run: | 34 | RUSTDOCFLAGS="--cfg docsrs" \ 35 | cargo doc --no-deps --all-features --workspace 36 | # Write index.html with redirect 37 | echo '' > ./target/doc/index.html 38 | 39 | - name: Deploy 40 | uses: actions/upload-artifact@v4 41 | with: 42 | name: documentation 43 | path: target/doc 44 | if-no-files-found: error 45 | retention-days: 1 46 | 47 | - name: Write CNAME file 48 | run: echo 'doc.libmakelib.com' > ./target/doc/CNAME 49 | 50 | - name: Deploy to GitHub Pages 51 | uses: peaceiris/actions-gh-pages@v4 52 | with: 53 | cname: true 54 | commit_message: Deploy documentation at ${{ github.sha }} 55 | github_token: ${{ secrets.GITHUB_TOKEN }} 56 | publish_branch: gh-pages 57 | publish_dir: ./target/doc 58 | user_email: actions@users.noreply.github.com 59 | user_name: github-actions 60 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: 🧪 Lint 2 | 3 | on: 4 | push: 5 | branches: 6 | - feat/libmake 7 | pull_request: 8 | branches: 9 | - feat/libmake 10 | release: 11 | types: [created] 12 | 13 | jobs: 14 | all: 15 | name: Lint 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: hecrj/setup-rust-action@v2 19 | with: 20 | components: clippy 21 | - uses: actions/checkout@v4 22 | - name: Check lints 23 | run: cargo clippy --workspace --all-features --all-targets --no-deps -- -D warnings 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.profraw 3 | *.log 4 | /.vscode/ 5 | /target/ 6 | build 7 | Cargo.lock 8 | Icon? 9 | src/.DS_Store 10 | /my_library/ 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to `LibMake` 2 | 3 | Welcome! We're thrilled that you're interested in contributing to the `LibMake` library. Whether you're looking to evangelize, submit feedback, or contribute code, we appreciate your involvement in making `LibMake` a better tool for everyone. Here's how you can get started. 4 | 5 | ## Evangelize 6 | 7 | One of the simplest ways to help us out is by spreading the word about LibMake. 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 LibMake, please let them know! 8 | 9 | ## How to Contribute 10 | 11 | If you're interested in making a more direct contribution, there are several ways you can help us improve LibMake. Here are some guidelines for submitting feedback, bug reports, and code contributions. 12 | 13 | ### Feedback 14 | 15 | Your feedback is incredibly valuable to us, and we're always looking for ways to make LibMake better. If you have ideas, suggestions, or questions about LibMake, we'd love to hear them. Here's how you can provide feedback: 16 | 17 | - Click [here][2] to submit a new feedback. 18 | - Use a descriptive title that clearly summarizes your feedback. 19 | - Provide a detailed description of the issue or suggestion. 20 | - Be patient while we review and respond to your feedback. 21 | 22 | ### Bug Reports 23 | 24 | If you encounter a bug while using LibMake, please let us know so we can fix it. Here's how you can submit a bug report: 25 | 26 | - Click [here][2] to submit a new issue. 27 | - Use a descriptive title that clearly summarizes the bug. 28 | - Provide a detailed description of the issue, including steps to reproduce it. 29 | - Be patient while we review and respond to your bug report. 30 | 31 | ### Code Contributions 32 | 33 | If you're interested in contributing code to LibMake, we're excited to have your help! Here's what you need to know: 34 | 35 | #### Feature Requests 36 | 37 | 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 LibMake: 38 | 39 | - Fork the repo. 40 | - Clone the LibMake[1] repo by running: 41 | `git clone {repository}` 42 | - Edit files in the `src/` folder. The `src/` folder contains the source code for LibMake. 43 | - Submit a pull request, and we'll review and merge your changes if they fit with our vision for LibMake. 44 | 45 | #### Submitting Code 46 | 47 | 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: 48 | 49 | - Fork the repo. 50 | - Clone the LibMake repo by running: 51 | `git clone {repository}` 52 | - Edit files in the `src/` folder. The `src/` folder contains the source code for LibMake. 53 | - Submit a pull request, and we'll review and merge your changes if they fit with our vision for LibMake. 54 | 55 | We hope that this guide has been helpful in explaining how you can contribute to LibMake. Thank you for your interest and involvement in our project! 56 | 57 | [1]: https://github.com/sebastienrousseau/libmake 58 | [2]: https://github.com/sebastienrousseau/libmake/issues/new 59 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | # Metadata about the package. 3 | authors = ["The LibMake (LM) library contributors "] 4 | build = "build.rs" 5 | categories = ["development-tools", "command-line-utilities", "template-engine"] 6 | description = """ 7 | A code generator to reduce repetitive tasks and build high-quality Rust 8 | libraries and applications, by providing a simple interface to create 9 | projects, generate code, and manage dependencies. 10 | """ 11 | documentation = "https://docs.rs/libmake" 12 | edition = "2021" 13 | exclude = [ 14 | "/.git/*", 15 | "/.github/*", 16 | "/.gitignore", 17 | "/.vscode/*" 18 | ] 19 | homepage = "https://libmake.com" 20 | include = [ 21 | "/CONTRIBUTING.md", 22 | "/LICENSE-APACHE", 23 | "/LICENSE-MIT", 24 | "/benches/**", 25 | "/build.rs", 26 | "/Cargo.toml", 27 | "/examples/**", 28 | "/README.md", 29 | "/src/**", 30 | "/tests/**", 31 | ] 32 | keywords = [ 33 | 'code-generation', 34 | 'generator', 35 | 'library', 36 | 'project-creation', 37 | 'scaffolding', 38 | ] 39 | license = "MIT OR Apache-2.0" 40 | name = "libmake" 41 | readme = "README.md" 42 | repository = "https://github.com/sebastienrousseau/libmake.git" 43 | rust-version = "1.60" 44 | version = "0.2.6" 45 | 46 | [[bench]] 47 | # Benchmarking configuration. 48 | name = "benchmark" 49 | harness = false 50 | path = "benches/criterion.rs" 51 | 52 | [profile.bench] 53 | debug = true 54 | 55 | [[example]] 56 | # Example configuration. 57 | name = "libmake" 58 | path = "examples/example.rs" 59 | 60 | [dependencies] 61 | # The dependencies of the package. 62 | anyhow = "1.0.83" 63 | assert_cmd = "2.0.14" 64 | clap = "4.5.4" 65 | configparser = "3.0.4" 66 | csv = "1.3.0" 67 | dtt = "0.0.6" 68 | env_logger = "0.11.3" 69 | figlet-rs = "0.1.5" 70 | log = {version="0.4.21", features = ["std"] } 71 | regex = "1.10.4" 72 | reqwest = { version = "0.12.4", features = ["blocking"] } 73 | rlg = "0.0.4" 74 | serde = { version = "1.0.202", features = ["derive"] } 75 | serde_ini = "0.2.0" 76 | serde_json = "1.0.117" 77 | serde_yml = "0.0.7" 78 | tempfile = "3.10.1" 79 | toml = "0.8.13" 80 | uuid = { version = "1.8.0", features = ["v4"] } 81 | vrd = "0.0.7" 82 | 83 | [dev-dependencies] 84 | # The dev-dependencies of the package. 85 | criterion = "0.5.1" 86 | predicates = "3.1.0" 87 | 88 | [lib] 89 | # Metadata about the library. 90 | crate-type = ["lib"] 91 | name = "libmake" 92 | path = "src/lib.rs" 93 | required-features = [] 94 | 95 | [features] 96 | # The features of the package. 97 | default = [] 98 | 99 | [package.metadata.docs.rs] 100 | targets = ["x86_64-unknown-linux-gnu"] 101 | rustdoc-args = ["--generate-link-to-definition"] 102 | 103 | # Linting config 104 | [lints.rust] 105 | 106 | ## Warn 107 | # box_pointers = "warn" 108 | missing_copy_implementations = "warn" 109 | missing_docs = "warn" 110 | unstable_features = "warn" 111 | # unused_crate_dependencies = "warn" 112 | unused_extern_crates = "warn" 113 | unused_results = "warn" 114 | 115 | ## Allow 116 | bare_trait_objects = "allow" 117 | elided_lifetimes_in_paths = "allow" 118 | non_camel_case_types = "allow" 119 | non_upper_case_globals = "allow" 120 | trivial_bounds = "allow" 121 | unsafe_code = "allow" 122 | 123 | ## Forbid 124 | missing_debug_implementations = "forbid" 125 | non_ascii_idents = "forbid" 126 | unreachable_pub = "forbid" 127 | 128 | ## Deny 129 | dead_code = "deny" 130 | deprecated_in_future = "deny" 131 | ellipsis_inclusive_range_patterns = "deny" 132 | explicit_outlives_requirements = "deny" 133 | future_incompatible = { level = "deny", priority = -1 } 134 | keyword_idents = "deny" 135 | macro_use_extern_crate = "deny" 136 | meta_variable_misuse = "deny" 137 | missing_fragment_specifier = "deny" 138 | noop_method_call = "deny" 139 | pointer_structural_match = "deny" 140 | rust_2018_idioms = { level = "deny", priority = -1 } 141 | rust_2021_compatibility = { level = "deny", priority = -1 } 142 | single_use_lifetimes = "deny" 143 | trivial_casts = "deny" 144 | trivial_numeric_casts = "deny" 145 | unused = { level = "deny", priority = -1 } 146 | unused_features = "deny" 147 | unused_import_braces = "deny" 148 | unused_labels = "deny" 149 | unused_lifetimes = "deny" 150 | unused_macro_rules = "deny" 151 | unused_qualifications = "deny" 152 | variant_size_differences = "deny" 153 | 154 | [package.metadata.clippy] 155 | warn-lints = ["clippy::all", "clippy::pedantic", "clippy::cargo", "clippy::nursery"] 156 | 157 | [profile.dev] 158 | codegen-units = 256 159 | debug = true 160 | debug-assertions = true 161 | incremental = true 162 | lto = false 163 | opt-level = 0 164 | overflow-checks = true 165 | panic = 'unwind' 166 | rpath = false 167 | strip = false 168 | 169 | [profile.release] 170 | codegen-units = 1 171 | debug = false 172 | debug-assertions = false 173 | incremental = false 174 | lto = true 175 | opt-level = "s" 176 | overflow-checks = false 177 | panic = "abort" 178 | rpath = false 179 | strip = "symbols" 180 | 181 | [profile.test] 182 | codegen-units = 256 183 | debug = true 184 | debug-assertions = true 185 | incremental = true 186 | lto = false 187 | opt-level = 0 188 | overflow-checks = true 189 | rpath = false 190 | strip = false 191 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-2023 Sebastien Rousseau 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | LibMake logo 5 | 6 | 7 | 8 | # LibMake v0.2.6 🦀 9 | 10 | A code generator to reduce repetitive tasks and build high-quality Rust libraries. 11 | 12 | *Part of the [Mini Functions][00] family of libraries.* 13 | 14 | 15 |
16 | 17 | 18 | ![Libmake Banner][banner] 19 | 20 | [![Made With Rust][made-with-rust-badge]][09] [![Crates.io][crates-badge]][06] [![Lib.rs][libs-badge]][08] [![Docs.rs][docs-badge]][07] 21 | [![License][license-badge]][02] [![Codecov][codecov-badge]][10] 22 | 23 | • [Website][01] • [Documentation][07] • [Report Bug][03] • [Request Feature][03] • [Contributing Guidelines][04] 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | ## Overview 📖 32 | 33 | `LibMake` is a tool designed to quickly help creating high-quality Rust libraries by generating a set of pre-filled and pre-defined templated files. This opinionated boilerplate scaffolding tool aims to greatly reduces development time and minimizes repetitive tasks, allowing you to focus on your business logic while enforcing standards, best practices, consistency, and providing style guides for your library. 34 | 35 | With `LibMake`, you can easily generate a new Rust library code base structure with all the necessary files, layouts, build configurations, code, tests, benchmarks, documentation, and much more in a matter of seconds. 36 | 37 | The library is designed to be used as a command-line tool. It is available on [Crates.io][05] and [Lib.rs][06]. 38 | 39 | ## Features ✨ 40 | 41 | `LibMake` offers the following features and benefits: 42 | 43 | - Create your Rust library with ease using the command line interface or by providing a configuration file in CSV, JSON, TOML, or YAML format. 44 | - Rapidly generate new library projects with a pre-defined structure and boilerplate code that you can customize with your own template. 45 | - Generate a library pre-defined GitHub Actions workflow to help you automate your library development and testing. 46 | - Automatically generate basic functions, methods, and macros to get you started with your Rust library. 47 | - Enforce best practices and standards with starter documentation, test suites, and benchmark suites that are designed to help you get up and running quickly. 48 | 49 | ## Changelog 📚 50 | 51 | [00]: https://minifunctions.com/libmake "Mini Functions" 52 | [01]: https://libmake.com "LibMake" 53 | [02]: http://opensource.org/licenses/MIT "MIT license" 54 | [03]: https://github.com/sebastienrousseau/libmake/issues "Issues" 55 | [04]: https://github.com/sebastienrousseau/libmake/blob/main/CONTRIBUTING.md "Contributing" 56 | [05]: http://semver.org/ "Semantic Versioning" 57 | [06]: https://crates.io/crates/libmake "LibMake on Crates.io" 58 | [07]: https://docs.rs/libmake "LibMake on docs.rs" 59 | [08]: https://lib.rs/crates/libmake "LibMake on lib.rs" 60 | [09]: https://www.rust-lang.org "The Rust Programming Language" 61 | [10]: https://codecov.io/gh/sebastienrousseau/libmake "Codecov" 62 | 63 | [banner]: https://kura.pro/libmake/images/titles/title-libmake.svg "LibMake Banner" 64 | [codecov-badge]: https://img.shields.io/codecov/c/github/sebastienrousseau/libmake?style=for-the-badge&token=Q9KJ6XXL67 "Codecov Badge" 65 | [crates-badge]: https://img.shields.io/crates/v/libmake.svg?style=for-the-badge "Crates.io Badge" 66 | [docs-badge]: https://img.shields.io/docsrs/libmake.svg?style=for-the-badge "Docs.rs Badge" 67 | [libs-badge]: https://img.shields.io/badge/lib.rs-v0.2.6-orange.svg?style=for-the-badge "Lib.rs Badge" 68 | [license-badge]: https://img.shields.io/crates/l/libmake.svg?style=for-the-badge "License Badge" 69 | [made-with-rust-badge]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust "Made With Rust Badge" 70 | -------------------------------------------------------------------------------- /benches/criterion.rs: -------------------------------------------------------------------------------- 1 | //! # Benchmark: libmake 2 | //! 3 | //! This benchmark tests the performance of the `libmake` crate using the Criterion library. 4 | //! It measures the execution time of the `run` function from the `libmake` crate. 5 | //! 6 | //! ## Purpose 7 | //! 8 | //! The purpose of this benchmark is to assess the execution time of the `run` function 9 | //! from the `libmake` crate under controlled conditions. It helps identify any potential 10 | //! performance bottlenecks and allows for optimization if needed. 11 | //! 12 | //! ## Usage 13 | //! 14 | //! To run this benchmark, ensure that you have the `criterion` and `libmake` crates 15 | //! included as dependencies in your project's `Cargo.toml` file. 16 | //! 17 | //! In your project's code, you can use the `criterion_group` and `criterion_main` macros 18 | //! to define and run benchmarks. In this specific benchmark, the `libmake_benchmark` function 19 | //! is defined to measure the execution time of the `run` function. 20 | //! 21 | //! ```rust 22 | //! extern crate criterion; 23 | //! extern crate libmake; 24 | //! 25 | //! use criterion::{criterion_group, criterion_main, Criterion}; 26 | //! use libmake::run; 27 | //! 28 | //! fn libmake_benchmark(c: &mut Criterion) { 29 | //! c.bench_function("libmake", |b| b.iter(run)); 30 | //! } 31 | //! 32 | //! criterion_group!(benches, libmake_benchmark); 33 | //! criterion_main!(benches); 34 | //! ``` 35 | //! 36 | //! Running this benchmark will provide performance metrics for the `run` function 37 | //! from the `libmake` crate, helping you evaluate and optimize its performance. 38 | 39 | #![allow(missing_docs)] 40 | 41 | use criterion::{criterion_group, criterion_main, Criterion}; 42 | use libmake::run; 43 | 44 | #[allow(unused_results)] 45 | fn libmake_benchmark(c: &mut Criterion) { 46 | c.bench_function("libmake", |b| b.iter(run)); 47 | } 48 | 49 | criterion_group!(benches, libmake_benchmark); 50 | criterion_main!(benches); 51 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | //! This is the main function for the build script. 7 | //! 8 | //! Currently, it only instructs Cargo to re-run this build script if `build.rs` is changed. 9 | fn main() { 10 | // Avoid unnecessary re-building. 11 | println!("cargo:rerun-if-changed=build.rs"); 12 | } 13 | -------------------------------------------------------------------------------- /deny.toml: -------------------------------------------------------------------------------- 1 | [licenses] 2 | # The lint level for crates which do not have a detectable license 3 | unlicensed = "deny" 4 | 5 | # List of explicitly allowed licenses 6 | # See https://spdx.org/licenses/ for list of possible licenses 7 | # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. 8 | allow = [ 9 | "Apache-2.0", 10 | "MIT", 11 | "CC0-1.0", 12 | "ISC", 13 | "0BSD", 14 | "BSD-2-Clause", 15 | "BSD-3-Clause", 16 | "Unlicense", 17 | "Unicode-DFS-2016", 18 | ] 19 | 20 | # List of banned licenses 21 | [bans] 22 | multiple-versions = "deny" 23 | 24 | 25 | # The lint level for licenses considered copyleft 26 | copyleft = "deny" 27 | 28 | # Blanket approval or denial for OSI-approved or FSF Free/Libre licenses 29 | # * both - The license will only be approved if it is both OSI-approved *AND* FSF/Free 30 | # * either - The license will be approved if it is either OSI-approved *OR* FSF/Free 31 | # * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF/Free 32 | # * fsf-only - The license will be approved if is FSF/Free *AND NOT* OSI-approved 33 | # * neither - The license will be denied if is FSF/Free *OR* OSI-approved 34 | allow-osi-fsf-free = "either" 35 | 36 | # The confidence threshold for detecting a license from license text. 37 | # The higher the value, the more closely the license text must be to the 38 | # canonical license text of a valid SPDX license file. 39 | # [possible values: any between 0.0 and 1.0]. 40 | confidence-threshold = 0.8 41 | 42 | # The graph highlighting used when creating dotgraphs for crates 43 | # with multiple versions 44 | # * lowest-version - The path to the lowest versioned duplicate is highlighted 45 | # * simplest-path - The path to the version with the fewest edges is highlighted 46 | # * all - Both lowest-version and simplest-path are used 47 | highlight = "all" 48 | 49 | # List of crates that are allowed. Use with care! 50 | allow = [] 51 | 52 | # List of crates to deny 53 | deny = [ 54 | # Each entry the name of a crate and a version range. If version is 55 | # not specified, all versions will be matched. 56 | ] 57 | 58 | # Certain crates/versions that will be skipped when doing duplicate detection. 59 | skip = [] 60 | 61 | # Similarly to `skip` allows you to skip certain crates during duplicate detection, 62 | # unlike skip, it also includes the entire tree of transitive dependencies starting at 63 | # the specified crate, up to a certain depth, which is by default infinite 64 | skip-tree = [] 65 | 66 | 67 | [advisories] 68 | notice = "deny" 69 | unmaintained = "deny" 70 | unsound = "deny" 71 | vulnerability = "deny" 72 | -------------------------------------------------------------------------------- /examples/example.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | //! This is an example crate for LibMake. 7 | //! 8 | //! This crate provides various modules and examples for demonstrating the functionality 9 | //! of LibMake. Each module focuses on a specific feature or functionality. 10 | //! 11 | //! Copyright © 2023-2024 LibMake. All rights reserved. 12 | //! 13 | //! Dual-licensed under the terms of the Apache License, Version 2.0, or the MIT License, 14 | //! at your option. See the 'LICENSE' file for details. 15 | 16 | // Module Declarations 17 | // Each `mod` statement declares a module in the current crate. 18 | // Modules help organize code into separate namespaces, each focusing on specific functionalities. 19 | 20 | /// This is a module for the example `generate_from_args`. 21 | mod generate_from_args; 22 | 23 | /// This is a module for the example `generate_from_config`. 24 | mod generate_from_config; 25 | 26 | /// This is a module for the example `generate_from_csv`. 27 | mod generate_from_csv; 28 | 29 | /// This is a module for the example `generate_from_json`. 30 | mod generate_from_json; 31 | 32 | /// This is a module for the example `generate_from_toml`. 33 | mod generate_from_toml; 34 | 35 | /// This is a module for the example `generate_from_yaml`. 36 | mod generate_from_yaml; 37 | 38 | /// This is a module for the example `get_csv_field`. 39 | mod get_csv_field; 40 | 41 | /// This is a module for the example `get_json_field`. 42 | mod get_json_field; 43 | 44 | /// This is a module for the example `get_yaml_field`. 45 | mod get_yaml_field; 46 | 47 | // Main Function 48 | // The `main` function serves as the entry point of the program. 49 | // Here, it calls the `main` function of each module to execute their respective examples. 50 | 51 | /// The main function that runs all the example modules. 52 | fn main() { 53 | // Run the example module `generate_from_args`. 54 | generate_from_args::main(); 55 | 56 | // Run the example module `generate_from_config`. 57 | generate_from_config::main(); 58 | 59 | // Run the example module `generate_from_csv`. 60 | generate_from_csv::main(); 61 | 62 | // Run the example module `generate_from_json`. 63 | generate_from_json::main(); 64 | 65 | // Run the example module `generate_from_toml`. 66 | generate_from_toml::main(); 67 | 68 | // Run the example module `generate_from_yaml`. 69 | generate_from_yaml::main(); 70 | 71 | // Run the example module `get_csv_field`. 72 | get_csv_field::main(); 73 | 74 | // Run the example module `get_json_field`. 75 | get_json_field::main(); 76 | 77 | // Run the example module `get_yaml_field`. 78 | get_yaml_field::main(); 79 | } 80 | -------------------------------------------------------------------------------- /examples/generate_from_args.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | //! A simple test program for the `generate_from_args` function. 7 | //! 8 | //! This program simulates command line arguments and calls the `generate_from_args` function 9 | //! to generate files based on the provided arguments. 10 | //! 11 | //! # Arguments 12 | //! 13 | //! * `--author=` - The author name for the generated files. 14 | //! * `--output=` - The output directory for the generated files. 15 | //! 16 | //! # Example 17 | //! 18 | //! To run this test program, use the following command: 19 | //! 20 | //! ``` 21 | //! $ cargo run --release 22 | //! ``` 23 | //! 24 | //! Make sure to replace `` with the desired values for `--author` and `--output`. 25 | //! 26 | //! If successful, this program will print "Successfully generated files!". 27 | //! 28 | //! If there is an error, it will print an error message. 29 | 30 | // Import the necessary function for generating files from arguments 31 | use libmake::generators::args::generate_from_args; 32 | 33 | /// A simple test program for the `generate_from_args` function. 34 | /// 35 | /// This program simulates command line arguments and calls the `generate_from_args` function 36 | /// to generate files based on the provided arguments. 37 | /// 38 | /// # Arguments 39 | /// 40 | /// * `--author=` - The author name for the generated files. 41 | /// * `--output=` - The output directory for the generated files. 42 | /// 43 | /// # Example 44 | /// 45 | /// To run this test program, use the following command: 46 | /// 47 | /// ``` 48 | /// $ cargo run --release 49 | /// ``` 50 | /// 51 | /// Make sure to replace `` with the desired values for `--author` and `--output`. 52 | /// 53 | /// If successful, this program will print "Successfully generated files!". 54 | /// 55 | /// If there is an error, it will print an error message. 56 | pub(crate) fn main() { 57 | // Simulate command line arguments 58 | let args = "--author=Me --output=my_library" 59 | .split(' ') 60 | .map(ToString::to_string) // Directly using the method 61 | .collect::>(); 62 | 63 | // Check if there are at least two arguments (program name and at least one option) 64 | if args.len() < 2 { 65 | eprintln!("Usage: {} ", args[0]); 66 | return; 67 | } 68 | 69 | // Join the arguments (excluding the program name) into a single string 70 | let args_str = args[1..].join(" "); 71 | 72 | // Call the `generate_from_args` function with the arguments string 73 | let result = generate_from_args(&args_str); 74 | println!("{result:?}"); 75 | 76 | // Check the result of the function call and print a message accordingly 77 | match result { 78 | Ok(()) => println!("Successfully generated files!"), 79 | Err(err) => eprintln!("Error: {err}"), 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /examples/generate_from_config.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | //! # Example: Generating Templates from a Configuration File 7 | //! 8 | //! This is an example that demonstrates how to generate template files 9 | //! based on a configuration file using the `generate_from_config` function. 10 | //! 11 | //! ## Usage 12 | //! 13 | //! To run this example, make sure you have a valid configuration file at the specified path. 14 | //! The example allows you to define the file type (e.g., "yaml") and the file path. 15 | //! It then calls the `generate_from_config` function with the file path and file type as parameters. 16 | //! 17 | //! If generation is successful, it does nothing (the template files are created). 18 | //! If there is an error during generation, it prints an error message. 19 | //! 20 | //! ```rust 21 | //! use libmake::generator::generate_from_config; 22 | //! 23 | //! // Define the file path for the configuration file. 24 | //! let file_path = "./tests/data/mylibrary.yaml"; 25 | //! 26 | //! // Define the file type, which is "yaml" in this case. 27 | //! let file_type = "yaml"; 28 | //! 29 | //! // Call the generate_from_config function with the file_path and file_type. 30 | //! // This function generates template files based on the configuration. 31 | //! match generate_from_config(file_path, file_type) { 32 | //! // If generation is successful, do nothing (the template files are created). 33 | //! Ok(_) => (), 34 | //! // If there is an error during generation, print an error message. 35 | //! Err(err) => eprintln!("Error: {}", err), 36 | //! } 37 | //! ``` 38 | 39 | use libmake::generator::generate_from_config; 40 | 41 | /// Generate template files based on a configuration file. 42 | /// 43 | /// # Arguments 44 | /// 45 | /// * `file_path` - Path to the configuration file. 46 | /// * `file_type` - Type of the configuration file (e.g., "yaml"). 47 | /// 48 | /// # Returns 49 | /// 50 | /// * `Ok(())` - If generation is successful. 51 | /// * `Err(String)` - If there is an error during generation. 52 | pub(crate) fn main() { 53 | // Define the file path for the configuration file. 54 | let file_path = "./tests/data/mylibrary.yaml"; 55 | 56 | // Define the file type, which is "yaml" in this case. 57 | let file_type = "yaml"; 58 | 59 | // Call the generate_from_config function with the file_path and file_type. 60 | // This function generates template files based on the configuration. 61 | match generate_from_config(file_path, file_type) { 62 | // If generation is successful, do nothing (the template files are created). 63 | Ok(()) => (), 64 | // If there is an error during generation, print an error message. 65 | Err(err) => eprintln!("Error: {err}"), 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /examples/generate_from_csv.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | //! # Example: Generating Templates from a CSV File 7 | //! 8 | //! This is a simple test that demonstrates how to generate files from a CSV file 9 | //! using the `generate_from_csv` function. It attempts to generate template files 10 | //! from a CSV file and expects the operation to be successful. 11 | //! 12 | //! ## Usage 13 | //! 14 | //! To run this example, make sure you have a valid CSV file at the specified path. 15 | //! The example will attempt to generate template files based on the CSV data. 16 | //! If generation fails, it will print an error message. 17 | //! 18 | //! ```rust 19 | //! // Import the necessary function for generating templates from a CSV file. 20 | //! use libmake::generator::generate_from_csv; 21 | //! 22 | //! /// This is a simple test for generating files from a CSV file using the `generate_from_csv` function. 23 | //! /// It attempts to generate template files from a CSV file and expects the operation to be successful. 24 | //! // Define the path to the CSV file to be used for testing. 25 | //! let csv_file_path = "./tests/data/mylibrary.csv"; 26 | //! 27 | //! // Attempt to generate template files from the specified CSV file. 28 | //! // If successful, it indicates that the generation process worked as expected. 29 | //! generate_from_csv(csv_file_path) 30 | //! .expect("Failed to generate the template files"); 31 | //! ``` 32 | 33 | // Import the necessary function for generating templates from a CSV file. 34 | use libmake::generators::csv::generate_from_csv; 35 | 36 | /// Attempts to generate template files from the specified CSV file. 37 | /// 38 | /// # Parameters 39 | /// 40 | /// * `csv_file_path` - The path to the CSV file that contains the template generation information. 41 | /// 42 | /// # Returns 43 | /// 44 | /// * `Result<()>` - Returns `Ok(())` if the template generation process was successful, or returns an error if it failed. 45 | /// 46 | /// # Examples 47 | /// 48 | /// The following example demonstrates how to use the `generate_from_csv` function: 49 | /// 50 | /// ```rust 51 | /// use libmake::generators::csv::generate_from_csv; 52 | /// 53 | /// let csv_file_path = "./tests/data/mylibrary.csv"; 54 | /// 55 | /// // Attempt to generate template files from the specified CSV file. 56 | /// // If successful, it indicates that the generation process worked as expected. 57 | /// generate_from_csv(csv_file_path) 58 | /// .expect("Failed to generate the template files"); 59 | /// ``` 60 | pub(crate) fn main() { 61 | // Define the path to the CSV file to be used for testing. 62 | let csv_file_path = "./tests/data/mylibrary.csv"; 63 | 64 | // Attempt to generate template files from the specified CSV file. 65 | // If successful, it indicates that the generation process worked as expected. 66 | generate_from_csv(csv_file_path) 67 | .expect("Failed to generate the template files"); 68 | } 69 | -------------------------------------------------------------------------------- /examples/generate_from_json.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | //! # Example: Generating Templates from a JSON File 7 | //! 8 | //! This example demonstrates how to use the `generate_from_json` function from the `libmake` crate 9 | //! to generate template files from a JSON file containing configuration data. 10 | //! 11 | //! ## Usage 12 | //! 13 | //! To run this example, ensure that you have a valid JSON file at the specified path. 14 | //! The example defines the path to the JSON file (`json_file_path`) and then calls 15 | //! the `generate_from_json` function with this path as a parameter. 16 | //! 17 | //! If the generation process is successful, it does nothing (the template files are created). 18 | //! If there is an error during generation, it prints an error message. 19 | //! 20 | //! ```rust 21 | //! // Import the necessary function for generating templates from a JSON file. 22 | //! use libmake::generator::generate_from_json; 23 | //! 24 | //! /// This test demonstrates how to use the `generate_from_json` function from the `libmake` crate 25 | //! /// to generate template files from a JSON file. 26 | //! 27 | //! // Define the path to the JSON file that contains configuration data. 28 | //! let json_file_path = "./tests/data/mylibrary.json"; 29 | //! 30 | //! // Generate template files based on the data in the JSON file. 31 | //! // If the generation process fails, an error message is printed. 32 | //! generate_from_json(json_file_path) 33 | //! .expect("Failed to generate the template files"); 34 | //! ``` 35 | 36 | // Import the necessary function for generating templates from a JSON file. 37 | use libmake::generators::json::generate_from_json; 38 | 39 | /// Generate template files based on the data in the JSON file. 40 | /// 41 | /// # Arguments 42 | /// 43 | /// * `json_file_path` - Path to the JSON file that contains the configuration data. 44 | /// 45 | /// # Returns 46 | /// 47 | /// * `Result<(), String>` - Returns `Ok(())` if the template files are generated successfully, or returns an error message if there is an error during generation. 48 | /// 49 | pub(crate) fn main() { 50 | // Define the path to the JSON file that contains configuration data. 51 | let json_file_path = "./tests/data/mylibrary.json"; 52 | 53 | // Generate template files based on the data in the JSON file. 54 | // If the generation process fails, an error message is printed. 55 | generate_from_json(json_file_path) 56 | .expect("Failed to generate the template files"); 57 | } 58 | -------------------------------------------------------------------------------- /examples/generate_from_toml.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | //! # Example: Generating Templates from a TOML File 7 | //! 8 | //! This is a simple example that demonstrates how to generate template files 9 | //! based on configuration stored in a TOML file using the `generate_from_toml` 10 | //! function. 11 | //! 12 | //! ## Usage 13 | //! 14 | //! To run this example, make sure you have a valid TOML configuration file 15 | //! at the specified path. The example will attempt to generate template files 16 | //! based on the configuration. If generation fails, it will print an error 17 | //! message. 18 | //! 19 | //! ```rust 20 | //! // Import the necessary function for generating templates from a TOML file. 21 | //! use libmake::generator::generate_from_toml; 22 | //! 23 | //! // Define the path to the TOML file containing configuration. 24 | //! let toml_file_path = "./tests/data/mylibrary.toml" 25 | //! // Generate template files based on the configuration in the TOML file. 26 | //! // If generation fails, it will print an error message. 27 | //! generate_from_toml(toml_file_path) 28 | //! .expect("Failed to generate the template files"); 29 | //! ``` 30 | //! 31 | // Import the necessary function for generating templates from a TOML file. 32 | use libmake::generators::toml::generate_from_toml; 33 | 34 | /// Generate template files based on the configuration in the TOML file. 35 | /// 36 | /// # Arguments 37 | /// 38 | /// * `toml_file_path` - Path to the TOML file containing the configuration. 39 | /// 40 | /// # Returns 41 | /// 42 | /// * `Result<(), String>` - Returns `Ok(())` if the template files are generated successfully, or returns an error message if generation fails. 43 | /// 44 | pub(crate) fn main() { 45 | // Define the path to the TOML file containing configuration. 46 | let toml_file_path = "./tests/data/mylibrary.toml"; 47 | 48 | // Generate template files based on the configuration in the TOML file. 49 | // If generation fails, it will print an error message. 50 | generate_from_toml(toml_file_path) 51 | .expect("Failed to generate the template files"); 52 | } 53 | -------------------------------------------------------------------------------- /examples/generate_from_yaml.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | //! # Example: Generating Templates from a YAML File 7 | //! 8 | //! This is a simple example that demonstrates how to use the `generate_from_yaml` function 9 | //! from the `libmake` crate to generate template files from a YAML file. 10 | //! 11 | //! ## Usage 12 | //! 13 | //! To run this example, make sure you have a valid YAML file at the specified path. 14 | //! The example specifies the path to the YAML file (`yaml_file_path`) and then calls 15 | //! the `generate_from_yaml` function with this path as a parameter. 16 | //! 17 | //! If the generation process is successful, it does nothing (the template files are created). 18 | //! If there is an error during generation, it prints an error message. 19 | //! 20 | //! ```rust 21 | //! // Import the necessary function for generating templates from a YAML file. 22 | //! use libmake::generator::generate_from_yaml; 23 | //! 24 | //! // Specify the path to the YAML file to be used for generating templates. 25 | //! let yaml_file_path = "./tests/data/mylibrary.yaml"; 26 | //! 27 | //! // Generate template files from the specified YAML file. 28 | //! generate_from_yaml(yaml_file_path) 29 | //! .expect("Failed to generate the template files"); 30 | //! ``` 31 | 32 | // Import the necessary function for generating templates from a YAML file. 33 | use libmake::generators::yaml::generate_from_yaml; 34 | 35 | /// Generate template files from the specified YAML file. 36 | /// 37 | /// # Arguments 38 | /// 39 | /// * `yaml_file_path` - Path to the YAML file to be used for generating templates. 40 | /// 41 | /// # Returns 42 | /// 43 | /// * `Result<(), String>` - Returns `Ok(())` if the template files are generated successfully, or returns an error message if there is an error during generation. 44 | /// 45 | pub(crate) fn main() { 46 | // Specify the path to the YAML file to be used for generating templates. 47 | let yaml_file_path = "./tests/data/mylibrary.yaml"; 48 | 49 | // Generate template files from the specified YAML file. 50 | generate_from_yaml(yaml_file_path) 51 | .expect("Failed to generate the template files"); 52 | } 53 | -------------------------------------------------------------------------------- /examples/get_csv_field.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | //! # Test: Retrieving a CSV Field 7 | //! 8 | //! This is a test that demonstrates how to retrieve a specific field from a CSV file 9 | //! using the `get_csv_field` function from the `libmake` crate. 10 | //! 11 | //! ## Purpose 12 | //! 13 | //! The purpose of this test is to show how to extract a CSV field at a specified index 14 | //! from a CSV file located at the specified path (`file_path`). 15 | //! 16 | //! ## Usage 17 | //! 18 | //! To run this test, ensure that you have a valid CSV file at the specified path. 19 | //! The test uses the `get_csv_field` function to retrieve the field at the specified index (0). 20 | //! It then prints the result. 21 | //! 22 | //! ```rust 23 | //! // Import the necessary function for retrieving a field from a CSV file. 24 | //! use libmake::utils::get_csv_field; 25 | //! 26 | //! // Specify the path to the CSV file. 27 | //! let file_path = "../tests/data/mylibrary.csv"; 28 | //! 29 | //! // Retrieve the CSV field at index 0 and print the result. 30 | //! println!( 31 | //! "🦀 get_csv_field, ✅ {:?}", 32 | //! get_csv_field(Some(file_path), 0) 33 | //! ); 34 | //! ``` 35 | 36 | // Title: Test: Retrieving a CSV Field 37 | use libmake::utils::get_csv_field; 38 | 39 | /// Retrieve CSV field 40 | /// 41 | /// # Arguments 42 | /// 43 | /// * `file_path` - Path to CSV file 44 | /// * `index` - Index of field to retrieve 45 | /// 46 | /// # Returns 47 | /// 48 | /// String containing the requested field 49 | /// 50 | pub(crate) fn main() { 51 | // Retrieve CSV field 52 | let file_path = "../tests/data/mylibrary.csv"; 53 | println!( 54 | "🦀 get_csv_field, ✅ {:?}", 55 | get_csv_field(Some(file_path), 0) 56 | ); 57 | } 58 | -------------------------------------------------------------------------------- /examples/get_json_field.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | //! # Test: Retrieving a Field from a CSV File 7 | //! 8 | //! This is a test that demonstrates how to retrieve a specific field from a CSV file 9 | //! using the `get_csv_field` function from the `libmake` crate. 10 | //! 11 | //! ## Purpose 12 | //! 13 | //! The purpose of this test is to show how to extract a CSV field (`field_title`) 14 | //! from a CSV file located at the specified path (`file_path`). 15 | //! 16 | //! ## Usage 17 | //! 18 | //! To run this test, ensure that you have a valid CSV file at the specified path. 19 | //! The test checks if the file exists and then uses the `get_csv_field` function 20 | //! to retrieve the specified CSV field. If the file exists and the field is found, 21 | //! it prints the field's value; otherwise, it prints an error message or an empty string. 22 | //! 23 | //! ```rust 24 | //! // Import the necessary function for retrieving a field from a CSV file. 25 | //! use libmake::utils::get_csv_field; 26 | //! use std::path::Path; 27 | //! 28 | //! // Specify the path to the CSV file. 29 | //! let file_path = "../tests/data/mylibrary.csv"; 30 | //! 31 | //! // Define the CSV field to retrieve. 32 | //! let field_title = "title"; 33 | //! 34 | //! // Check if the CSV file exists before retrieving the field. 35 | //! let value = if Path::new(file_path).exists() { 36 | //! // If the file exists, use the `get_csv_field` function to retrieve the field. 37 | //! match get_csv_field(Some(file_path), 0) { 38 | //! Some(values) => values.join(", "), 39 | //! None => { 40 | //! eprintln!("Error retrieving field: {}", field_title); 41 | //! String::new() 42 | //! } 43 | //! } 44 | //! } else { 45 | //! // If the file doesn't exist, set the value to an empty string. 46 | //! String::new() 47 | //! }; 48 | //! 49 | //! // Print the result. 50 | //! println!("🦀 get_csv_field, ✅ {}: {}", field_title, value); 51 | //! ``` 52 | 53 | // Title: Test: Retrieving a field from a CSV file 54 | use libmake::utils::get_csv_field; 55 | use std::path::Path; 56 | 57 | /// Retrieve CSV field 58 | /// 59 | /// # Arguments 60 | /// 61 | /// * `file_path` - Path to the CSV file 62 | /// * `field_title` - Name of the CSV field to retrieve 63 | /// 64 | /// # Returns 65 | /// 66 | /// The value of the CSV field, or an empty string if the file does not exist or the field cannot be found 67 | /// 68 | pub(crate) fn main() { 69 | // Retrieve CSV field 70 | let file_path = "../tests/data/mylibrary.csv"; 71 | let field_title = "title"; 72 | 73 | let value = if Path::new(file_path).exists() { 74 | match get_csv_field(Some(file_path), 0) { 75 | Some(values) => values.join(", "), 76 | None => { 77 | eprintln!("Error retrieving field: {field_title}"); 78 | String::new() 79 | } 80 | } 81 | } else { 82 | String::new() 83 | }; 84 | 85 | println!("🦀 get_csv_field, ✅ {field_title}: {value}"); 86 | } 87 | -------------------------------------------------------------------------------- /examples/get_yaml_field.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | //! # Test: Retrieving a Field from a YAML File 7 | //! 8 | //! This is a test that demonstrates how to retrieve a specific field from a YAML file 9 | //! using the `get_yaml_field` function from the `libmake` crate. 10 | //! 11 | //! ## Purpose 12 | //! 13 | //! The purpose of this test is to show how to extract a YAML field (`field_keywords`) 14 | //! from a YAML file located at the specified path (`file_path`). The test specifically 15 | //! handles YAML arrays and converts them into a formatted string. 16 | //! 17 | //! ## Usage 18 | //! 19 | //! To run this test, ensure that you have a valid YAML file at the specified path. 20 | //! The test checks if the file exists and then uses the `get_yaml_field` function 21 | //! to retrieve the specified YAML field (`field_keywords`). If the file exists and 22 | //! the field is found, it processes the field's content (assuming it's an array), 23 | //! formats it into a string, and prints the result. If the file doesn't exist, 24 | //! it prints an empty string. 25 | //! 26 | //! ```rust 27 | //! // Import the necessary function for retrieving a field from a YAML file. 28 | //! use libmake::utils::get_yaml_field; 29 | //! use std::error::Error; 30 | //! use std::path::Path; 31 | //! 32 | //! // Specify the path to the YAML file. 33 | //! let file_path = "../tests/data/mylibrary.yaml"; 34 | //! 35 | //! // Define the YAML field to retrieve. 36 | //! let field_keywords = "keywords"; 37 | //! 38 | //! // Check if the YAML file exists before retrieving the field. 39 | //! let value = if Path::new(file_path).exists() { 40 | //! // If the file exists, use the `get_yaml_field` function to retrieve the field. 41 | //! let keywords: Result, Box> = get_yaml_field(Some(file_path), field_keywords) 42 | //! .map(|s| s.split('\n') 43 | //! .map(|s| s.trim_start_matches("- ")) 44 | //! .filter(|s| !s.is_empty()) 45 | //! .map(|s| format!("\"{}\"", s)) 46 | //! .collect()); 47 | //! 48 | //! match keywords { 49 | //! Ok(keywords) => format!("[{}]", keywords.join(", ")), 50 | //! Err(e) => { 51 | //! eprintln!("Error retrieving keywords: {}", e); 52 | //! String::new() 53 | //! } 54 | //! } 55 | //! } else { 56 | //! // If the file doesn't exist, set the value to an empty string. 57 | //! String::new() 58 | //! }; 59 | //! 60 | //! // Print the result. 61 | //! println!("🦀 get_yaml_field, ✅ {}: {}", field_keywords, value); 62 | //! ``` 63 | 64 | // Title: Test: Retrieving a field from a YAML file 65 | use libmake::utils::get_yaml_field; 66 | use std::error::Error; 67 | use std::path::Path; 68 | 69 | /// # Test: Retrieving a Field from a YAML File 70 | /// 71 | /// This is a test that demonstrates how to retrieve a specific field from a YAML file 72 | /// using the `get_yaml_field` function from the `libmake` crate. 73 | /// 74 | /// ## Purpose 75 | /// 76 | /// The purpose of this test is to show how to extract a YAML field (`field_keywords`) 77 | /// from a YAML file located at the specified path (`file_path`). The test specifically 78 | /// handles YAML arrays and converts them into a formatted string. 79 | /// 80 | /// ## Usage 81 | /// 82 | /// To run this test, ensure that you have a valid YAML file at the specified path. 83 | /// The test checks if the file exists and then uses the `get_yaml_field` function 84 | /// to retrieve the specified YAML field (`field_keywords`). If the file exists and 85 | /// the field is found, it processes the field's content (assuming it's an array), 86 | /// formats it into a string, and prints the result. If the file doesn't exist, 87 | /// it prints an empty string. 88 | /// 89 | /// ```rust 90 | /// // Import the necessary function for retrieving a field from a YAML file. 91 | /// use libmake::utils::get_yaml_field; 92 | /// use std::error::Error; 93 | /// use std::path::Path; 94 | /// 95 | /// // Specify the path to the YAML file. 96 | /// let file_path = "../tests/data/mylibrary.yaml"; 97 | /// 98 | /// // Define the YAML field to retrieve. 99 | /// let field_keywords = "keywords"; 100 | /// 101 | /// // Check if the YAML file exists before retrieving the field. 102 | /// let value = if Path::new(file_path).exists() { 103 | /// // If the file exists, use the `get_yaml_field` function to retrieve the field. 104 | /// let keywords: Result, Box> = get_yaml_field(Some(file_path), field_keywords) 105 | /// .map(|s| s.split('\n') 106 | /// .map(|s| s.trim_start_matches("- ")) 107 | /// .filter(|s| !s.is_empty()) 108 | /// .map(|s| format!("\"{}\"", s)) 109 | /// .collect()); 110 | /// 111 | /// match keywords { 112 | /// Ok(keywords) => format!("[{}]", keywords.join(", ")), 113 | /// Err(e) => { 114 | /// eprintln!("Error retrieving keywords: {}", e); 115 | /// String::new() 116 | /// } 117 | /// } 118 | /// } else { 119 | /// // If the file doesn't exist, set the value to an empty string. 120 | /// String::new() 121 | /// }; 122 | /// 123 | /// // Print the result. 124 | /// println!("🦀 get_yaml_field, ✅ {}: {}", field_keywords, value); 125 | /// ``` 126 | /// 127 | pub(crate) fn main() { 128 | let file_path = "../tests/data/mylibrary.yaml"; 129 | let field_keywords = "keywords"; 130 | 131 | let value = if Path::new(file_path).exists() { 132 | let keywords: Result, Box> = 133 | get_yaml_field(Some(file_path), field_keywords).map(|s| { 134 | s.split('\n') 135 | .map(|s| s.trim_start_matches("- ")) 136 | .filter(|s| !s.is_empty()) 137 | .map(|s| format!("\"{s}\"")) 138 | .collect() 139 | }); 140 | 141 | match keywords { 142 | Ok(keywords) => format!("[{}]", keywords.join(", ")), 143 | Err(e) => { 144 | eprintln!("Error retrieving keywords: {e}"); 145 | String::new() 146 | } 147 | } 148 | } else { 149 | String::new() 150 | }; 151 | 152 | println!("🦀 get_yaml_field, ✅ {field_keywords}: {value}"); 153 | } 154 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2021" 2 | max_width = 72 3 | tab_spaces = 4 4 | use_field_init_shorthand = true 5 | -------------------------------------------------------------------------------- /src/cli.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | // use std::path::Path; 7 | 8 | use clap::{error::Error, Arg, ArgMatches, Command}; 9 | 10 | /// Constructs the command-line interface for the application using Clap, 11 | /// including all necessary arguments. 12 | /// 13 | /// # Examples 14 | /// 15 | /// ``` 16 | /// use libmake::cli; 17 | /// let matches = cli::build().expect("CLI parsing failed"); 18 | /// ``` 19 | /// 20 | /// # Errors 21 | /// 22 | /// This function will return an error if the command-line argument parsing fails. 23 | /// 24 | pub fn build() -> Result { 25 | let manual_args = vec![ 26 | create_arg_info("author", Some("Me"), "Sets the author of the library", 'a', "author", "AUTHOR"), 27 | create_arg_info("build", Some("build.rs"), "Sets the build script that is used to perform additional build-time operations.", 'b', "build", "BUILD"), 28 | create_arg_info("categories", Some("['category 1', 'category 2']"), "Sets the categories of the library", 'c', "categories", "CATEGORIES"), 29 | create_arg_info("description", Some("A library for doing things"), "Sets the description of the library", 'd', "description", "DESCRIPTION"), 30 | create_arg_info("documentation", Some("https://lib.rs/crates/my_library"), "Sets the documentation URL of the library", 'u', "documentation", "DOCUMENTATION"), 31 | create_arg_info("edition", Some("2021"), "Sets the edition of the library", 'e', "edition", "EDITION"), 32 | create_arg_info("email", Some("test@test.com"), "Sets the email of the library author", '@', "email", "EMAIL"), 33 | create_arg_info("homepage", Some("https://test.com"), "Sets the homepage of the library", 'p', "homepage", "HOMEPAGE"), 34 | create_arg_info("keywords", Some("['keyword1', 'keyword2']"), "Sets the keywords of the library", 'k', "keywords", "KEYWORDS"), 35 | create_arg_info("license", Some("MIT OR Apache-2.0"), "Sets the license of the library", 'l', "license", "LICENSE"), 36 | create_arg_info("name", Some("my_library"), "Sets the name of the library", 'n', "name", "NAME"), 37 | create_arg_info("output", Some("my_library"), "Sets the output directory for the library", 'o', "output", "OUTPUT"), 38 | create_arg_info("readme", Some("README.md"), "Sets the README file for the library", 'm', "readme", "README"), 39 | create_arg_info("repository", Some("https://github.com/example/my_library"), "Sets the repository URL of the library", 'g', "repository", "REPOSITORY"), 40 | create_arg_info("rustversion", Some("1.60"), "Sets the Rust version of the library", 'r', "rustversion", "RUSTVERSION"), 41 | create_arg_info("version", Some("0.2.6"), "Sets the version of the library", 'v', "version", "VERSION"), 42 | create_arg_info("website", Some("https://test.com"), "Sets the website of the library author", 'w', "website", "WEBSITE"), 43 | ]; 44 | 45 | let file_args = vec![ 46 | create_arg_info( 47 | "csv", 48 | Some(""), 49 | "Sets the CSV file to use for generating the library", 50 | 'x', 51 | "csv", 52 | "CSV", 53 | ), 54 | create_arg_info( 55 | "ini", 56 | Some(""), 57 | "Sets the INI file to use for generating the library", 58 | 'i', 59 | "ini", 60 | "INI", 61 | ), 62 | create_arg_info( 63 | "json", 64 | Some(""), 65 | "Sets the JSON file to use for generating the library", 66 | 'j', 67 | "json", 68 | "JSON", 69 | ), 70 | create_arg_info( 71 | "yaml", 72 | Some(""), 73 | "Sets the YAML file to use for generating the library", 74 | 'y', 75 | "yaml", 76 | "YAML", 77 | ), 78 | create_arg_info( 79 | "toml", 80 | Some(""), 81 | "Sets the TOML file to use for generating the library", 82 | 't', 83 | "toml", 84 | "TOML", 85 | ), 86 | ]; 87 | 88 | let command = Command::new("My Library") 89 | .author("Sebastien Rousseau") 90 | .about("A Rust library generator that helps create high-quality Rust libraries quickly and easily.") 91 | .after_help("By default, if no arguments are passed in, the CLI will throw an error. To see a list of available actions, run `--help`.") 92 | .subcommand( 93 | Command::new("manual") 94 | .about("Set library information manually") 95 | .args(manual_args.into_iter().map(create_arg).collect::>()), 96 | ) 97 | .subcommand( 98 | Command::new("file") 99 | .about("Set library information from a file") 100 | .args(file_args.into_iter().map(create_arg).collect::>()), 101 | ); 102 | 103 | // Assuming validate_args is a custom function that you have implemented 104 | let matches = command.clone().try_get_matches()?; 105 | 106 | Ok(matches) 107 | } 108 | 109 | /// Helper function to create a command-line argument. 110 | const fn create_arg_info( 111 | name: &'static str, 112 | default: Option<&'static str>, 113 | help: &'static str, 114 | short: char, 115 | long: &'static str, 116 | value_name: &'static str, 117 | ) -> ( 118 | &'static str, 119 | Option<&'static str>, 120 | &'static str, 121 | char, 122 | &'static str, 123 | &'static str, 124 | ) { 125 | (name, default, help, short, long, value_name) 126 | } 127 | 128 | /// Creates an argument based on provided information. 129 | pub fn create_arg( 130 | arg_info: ( 131 | &'static str, 132 | Option<&'static str>, 133 | &'static str, 134 | char, 135 | &'static str, 136 | &'static str, 137 | ), 138 | ) -> Arg { 139 | let (name, default, help, short, long, value_name) = arg_info; 140 | 141 | let mut arg = Arg::new(name) 142 | .help(help) 143 | .short(short) 144 | .long(long) 145 | .value_name(value_name); 146 | 147 | if let Some(default_value) = default { 148 | arg = arg.default_value(default_value); 149 | } 150 | arg 151 | } 152 | -------------------------------------------------------------------------------- /src/generators/args.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | generator::generate_files, 3 | models::model_params::FileGenerationParams, 4 | }; 5 | use std::io; 6 | 7 | /// Generates files for a new Rust project based on command line arguments. 8 | /// The arguments must be in the form `--name=value`. 9 | /// The following arguments are supported: 10 | /// - `author` - the author of the project (optional). 11 | /// - `build` - the build command to be used for building the project (optional). 12 | /// - `categories` - the categories that the project belongs to (optional). 13 | /// - `description` - a short description of the project (optional). 14 | /// - `documentation` - the documentation URL of the project (optional). 15 | /// - `edition` - the edition of the project (optional). 16 | /// - `email` - the email address of the author (optional). 17 | /// - `homepage` - the homepage of the project (optional). 18 | /// - `keywords` - keywords that describe the project (optional). 19 | /// - `license` - the license under which the project is released (optional). 20 | /// - `name` - the name of the project (optional). 21 | /// - `output` - the output directory where the project files will be created (required). 22 | /// - `readme` - the name of the readme file (optional). 23 | /// - `repository` - the url of the project's repository (optional). 24 | /// - `rustversion` - the minimum Rust version required by the project (optional). 25 | /// - `version` - the initial version of the project (optional). 26 | /// - `website` - the website of the project (optional). 27 | /// 28 | /// # Errors 29 | /// 30 | /// This function will return an error in the following situations: 31 | /// 32 | /// - If an invalid argument is provided. Each argument must be in the form `--name=value`. 33 | /// - If there is an error in generating files based on the parameters derived from the arguments. 34 | /// 35 | pub fn generate_from_args(args_str: &str) -> io::Result<()> { 36 | let args = args_str.split_whitespace(); 37 | let mut params = FileGenerationParams::default(); 38 | for arg in args { 39 | let mut parts = arg.splitn(2, '='); 40 | let name = parts.next().unwrap_or_default(); 41 | let value = parts.next().unwrap_or_default(); 42 | match name { 43 | "--author" => params.author = Some(value.to_string()), 44 | "--build" => params.build = Some(value.to_string()), 45 | "--categories" => { 46 | params.categories = Some(value.to_string()); 47 | } 48 | "--description" => { 49 | params.description = Some(value.to_string()); 50 | } 51 | "--documentation" => { 52 | params.documentation = Some(value.to_string()); 53 | } 54 | "--edition" => params.edition = Some(value.to_string()), 55 | "--email" => params.email = Some(value.to_string()), 56 | "--homepage" => params.homepage = Some(value.to_string()), 57 | "--keywords" => params.keywords = Some(value.to_string()), 58 | "--license" => params.license = Some(value.to_string()), 59 | "--name" => params.name = Some(value.to_string()), 60 | "--output" => params.output = Some(value.to_string()), 61 | "--readme" => params.readme = Some(value.to_string()), 62 | "--repository" => { 63 | params.repository = Some(value.to_string()); 64 | } 65 | "--rustversion" => { 66 | params.rustversion = Some(value.to_string()); 67 | } 68 | "--version" => params.version = Some(value.to_string()), 69 | "--website" => params.website = Some(value.to_string()), 70 | _ => { 71 | return Err(io::Error::new( 72 | io::ErrorKind::Other, 73 | format!("Invalid argument: {name}"), 74 | )) 75 | } 76 | } 77 | } 78 | println!("{params:?}"); 79 | generate_files(params)?; 80 | Ok(()) 81 | } 82 | -------------------------------------------------------------------------------- /src/generators/ascii.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | //! This module provides functionality for generating ASCII art from text using the FIGlet library. 7 | 8 | use crate::models::error_ascii_art::AsciiArtError; 9 | use figlet_rs::FIGfont; 10 | 11 | /// Generates ASCII art from the given text using the standard `FIGfont`. 12 | /// 13 | /// # Arguments 14 | /// 15 | /// * `text` - The text to convert to ASCII art. 16 | /// 17 | /// # Errors 18 | /// 19 | /// This function returns an `Err` in the following situations: 20 | /// 21 | /// - If the input `text` is empty (`ConversionError`). 22 | /// - If the standard `FIGfont` fails to load (`FontLoadError`). 23 | /// - If the text cannot be converted to ASCII art (`ConversionError`). 24 | /// 25 | /// # Examples 26 | /// 27 | /// ``` 28 | /// use libmake::generators::ascii::generate_ascii_art; 29 | /// 30 | /// let text = "Hello, world!"; 31 | /// let result = generate_ascii_art(text); 32 | /// assert!(result.is_ok()); 33 | /// ``` 34 | pub fn generate_ascii_art(text: &str) -> Result { 35 | if text.is_empty() { 36 | return Err(AsciiArtError::ConversionError); 37 | } 38 | 39 | let standard_font = load_standard_font()?; 40 | let figure = standard_font 41 | .convert(text) 42 | .ok_or(AsciiArtError::ConversionError)?; 43 | 44 | Ok(figure.to_string()) 45 | } 46 | 47 | /// Loads the standard FIGfont. 48 | /// 49 | /// # Errors 50 | /// 51 | /// This function returns an `Err` if the standard `FIGfont` fails to load (`FontLoadError`). 52 | /// 53 | /// # Examples 54 | /// 55 | /// ``` 56 | /// use libmake::generators::ascii::load_standard_font; 57 | /// 58 | /// let result = load_standard_font(); 59 | /// assert!(result.is_ok()); 60 | /// ``` 61 | pub fn load_standard_font() -> Result { 62 | FIGfont::standard().map_err(|_| AsciiArtError::FontLoadError) 63 | } 64 | -------------------------------------------------------------------------------- /src/generators/csv.rs: -------------------------------------------------------------------------------- 1 | use crate::macro_generate_files; 2 | use crate::models::model_params::FileGenerationParams; 3 | use csv::Reader; 4 | use std::io; 5 | 6 | /// Generates files for a new Rust project based on a CSV file. 7 | /// 8 | /// # Arguments 9 | /// 10 | /// The CSV file must contain the following columns: 11 | /// 12 | /// - `author` - the author of the project (optional). 13 | /// - `build` - the build command to be used for building the project (optional). 14 | /// - `categories` - the categories that the project belongs to (optional). 15 | /// - `description` - a short description of the project (optional). 16 | /// - `documentation` - the documentation URL of the project (optional). 17 | /// - `edition` - the edition of the project (optional). 18 | /// - `email` - the email address of the author (optional). 19 | /// - `homepage` - the homepage of the project (optional). 20 | /// - `keywords` - keywords that describe the project (optional). 21 | /// - `license` - the license under which the project is released (optional). 22 | /// - `name` - the name of the project (optional). 23 | /// - `output` - the output directory where the project files will be created (required). 24 | /// - `readme` - the name of the readme file (optional). 25 | /// - `repository` - the url of the project's repository (optional). 26 | /// - `rustversion` - the minimum Rust version required by the project (optional). 27 | /// - `version` - the initial version of the project (optional). 28 | /// - `website` - the website of the project (optional). 29 | /// 30 | /// # Errors 31 | /// 32 | /// This function will return an error in the following situations: 33 | /// 34 | /// - If the specified CSV file cannot be found, read, or is not valid CSV. 35 | /// - If an error occurs while parsing the CSV data into the `FileGenerationParams` struct. 36 | /// - If there is an error in generating files based on the parameters from each CSV record. 37 | /// 38 | pub fn generate_from_csv(path: &str) -> io::Result<()> { 39 | let mut reader = Reader::from_path(path)?; 40 | for result in reader.records() { 41 | let record = result?; 42 | let params = FileGenerationParams { 43 | author: record.get(0).map(ToString::to_string), 44 | build: record.get(1).map(ToString::to_string), 45 | categories: record.get(2).map(ToString::to_string), 46 | description: record.get(3).map(ToString::to_string), 47 | documentation: record.get(4).map(ToString::to_string), 48 | edition: record.get(5).map(ToString::to_string), 49 | email: record.get(6).map(ToString::to_string), 50 | homepage: record.get(7).map(ToString::to_string), 51 | keywords: record.get(8).map(ToString::to_string), 52 | license: record.get(9).map(ToString::to_string), 53 | name: record.get(10).map(ToString::to_string), 54 | output: record.get(11).map(ToString::to_string), 55 | readme: record.get(12).map(ToString::to_string), 56 | repository: record.get(13).map(ToString::to_string), 57 | rustversion: record.get(14).map(ToString::to_string), 58 | version: record.get(15).map(ToString::to_string), 59 | website: record.get(16).map(ToString::to_string), 60 | }; 61 | macro_generate_files!(params.clone()) 62 | .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; 63 | } 64 | Ok(()) 65 | } 66 | -------------------------------------------------------------------------------- /src/generators/ini.rs: -------------------------------------------------------------------------------- 1 | use crate::macro_generate_files; 2 | use crate::models::model_params::FileGenerationParams; 3 | use serde_ini::from_str; 4 | use std::fs; 5 | use std::io; 6 | 7 | /// Generates files for a new Rust project based on an INI file. 8 | /// 9 | /// The INI file must contain a single section with the following 10 | /// keys: 11 | /// - `author` - the author of the project (optional). 12 | /// - `build` - the build command to be used for building the project (optional). 13 | /// - `categories` - the categories that the project belongs to (optional). 14 | /// - `description` - a short description of the project (optional). 15 | /// - `documentation` - the documentation URL of the project (optional). 16 | /// - `edition` - the edition of the project (optional). 17 | /// - `email` - the email address of the author (optional). 18 | /// - `homepage` - the homepage of the project (optional). 19 | /// - `keywords` - keywords that describe the project (optional). 20 | /// - `license` - the license under which the project is released (optional). 21 | /// - `name` - the name of the project (optional). 22 | /// - `output` - the output directory where the project files will be created (required). 23 | /// - `readme` - the name of the readme file (optional). 24 | /// - `repository` - the url of the project's repository (optional). 25 | /// - `rustversion` - the minimum Rust version required by the project (optional). 26 | /// - `version` - the initial version of the project (optional). 27 | /// - `website` - the website of the project (optional). 28 | /// 29 | /// # Errors 30 | /// 31 | /// This function will return an error in the following situations: 32 | /// 33 | /// - If the specified INI file cannot be found, read, or is not valid UTF-8. 34 | /// - If the INI data cannot be parsed into the `FileGenerationParams` struct. 35 | /// - If there is an error in generating files based on the parameters. 36 | /// 37 | pub fn generate_from_ini(path: &str) -> io::Result<()> { 38 | let contents = fs::read_to_string(path)?; 39 | let params: FileGenerationParams = 40 | from_str(&contents).map_err(|e| { 41 | io::Error::new(io::ErrorKind::InvalidData, e.to_string()) 42 | })?; 43 | macro_generate_files!(params.clone()) 44 | .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; 45 | Ok(()) 46 | } 47 | -------------------------------------------------------------------------------- /src/generators/json.rs: -------------------------------------------------------------------------------- 1 | use crate::macro_generate_files; 2 | use crate::models::model_params::FileGenerationParams; 3 | use std::fs; 4 | use std::io; 5 | 6 | /// Generates files for a new Rust project based on a JSON file. 7 | /// 8 | /// # Arguments 9 | /// 10 | /// The JSON file must contain a single object with the following 11 | /// properties: 12 | /// 13 | /// - `author` - the author of the project (optional). 14 | /// - `build` - the build command to be used for building the project (optional). 15 | /// - `categories` - the categories that the project belongs to (optional). 16 | /// - `description` - a short description of the project (optional). 17 | /// - `documentation` - the documentation URL of the project (optional). 18 | /// - `edition` - the edition of the project (optional). 19 | /// - `email` - the email address of the author (optional). 20 | /// - `homepage` - the homepage of the project (optional). 21 | /// - `keywords` - keywords that describe the project (optional). 22 | /// - `license` - the license under which the project is released (optional). 23 | /// - `name` - the name of the project (optional). 24 | /// - `output` - the output directory where the project files will be created (required). 25 | /// - `readme` - the name of the readme file (optional). 26 | /// - `repository` - the url of the project's repository (optional). 27 | /// - `rustversion` - the minimum Rust version required by the project (optional). 28 | /// - `version` - the initial version of the project (optional). 29 | /// - `website` - the website of the project (optional). 30 | /// 31 | /// # Errors 32 | /// 33 | /// This function will return an error in the following situations: 34 | /// 35 | /// - If the specified JSON file cannot be found, read, or is not valid UTF-8. 36 | /// - If the JSON data cannot be deserialized into the `FileGenerationParams` struct. 37 | /// - If there is an error in generating files based on the parameters. 38 | /// 39 | pub fn generate_from_json(path: &str) -> io::Result<()> { 40 | let contents = fs::read_to_string(path)?; 41 | let params: FileGenerationParams = serde_json::from_str(&contents) 42 | .map_err(|e| { 43 | io::Error::new(io::ErrorKind::Other, e.to_string()) 44 | })?; 45 | macro_generate_files!(params.clone()) 46 | .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; 47 | Ok(()) 48 | } 49 | -------------------------------------------------------------------------------- /src/generators/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | /// The `ascii` module contains functionality for generating ASCII art from 7 | /// text using the FIGlet library. 8 | pub mod ascii; 9 | 10 | /// The `args` module contains functionality for parsing command-line arguments. 11 | pub mod args; 12 | 13 | /// The `csv` module contains functionality for parsing CSV files. 14 | pub mod csv; 15 | 16 | /// The `ini` module contains functionality for parsing INI files. 17 | pub mod ini; 18 | 19 | /// The `json` module contains functionality for parsing JSON files. 20 | pub mod json; 21 | 22 | /// The `toml` module contains functionality for parsing TOML files. 23 | pub mod toml; 24 | 25 | /// The `yaml` module contains functionality for parsing YAML files. 26 | pub mod yaml; 27 | -------------------------------------------------------------------------------- /src/generators/toml.rs: -------------------------------------------------------------------------------- 1 | use crate::macro_generate_files; 2 | use crate::models::model_params::FileGenerationParams; 3 | use std::fs; 4 | use std::io; 5 | 6 | /// Generates files for a new Rust project based on a TOML file. 7 | /// 8 | /// The TOML file must contain a single object with the following 9 | /// properties: 10 | /// 11 | /// - `author` - the author of the project (optional). 12 | /// - `build` - the build command to be used for building the project (optional). 13 | /// - `categories` - the categories that the project belongs to (optional). 14 | /// - `description` - a short description of the project (optional). 15 | /// - `documentation` - the documentation URL of the project (optional). 16 | /// - `edition` - the edition of the project (optional). 17 | /// - `email` - the email address of the author (optional). 18 | /// - `homepage` - the homepage of the project (optional). 19 | /// - `keywords` - keywords that describe the project (optional). 20 | /// - `license` - the license under which the project is released (optional). 21 | /// - `name` - the name of the project (optional). 22 | /// - `output` - the output directory where the project files will be created (required). 23 | /// - `readme` - the name of the readme file (optional). 24 | /// - `repository` - the url of the project's repository (optional). 25 | /// - `rustversion` - the minimum Rust version required by the project (optional). 26 | /// - version - the initial version of the project (optional). 27 | /// - website - the website of the project (optional). 28 | /// 29 | /// # Errors 30 | /// 31 | /// This function will return an error in the following situations: 32 | /// 33 | /// - If the specified TOML file cannot be found, read, or is not valid UTF-8. 34 | /// - If the TOML data cannot be deserialized into the FileGenerationParams struct. 35 | /// - If there is an error in generating files based on the parameters. 36 | /// 37 | pub fn generate_from_toml(path: &str) -> io::Result<()> { 38 | let contents = fs::read_to_string(path)?; 39 | let params: FileGenerationParams = toml::from_str(&contents) 40 | .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; 41 | macro_generate_files!(params.clone()) 42 | .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; 43 | Ok(()) 44 | } 45 | -------------------------------------------------------------------------------- /src/generators/yaml.rs: -------------------------------------------------------------------------------- 1 | use crate::macro_generate_files; 2 | use crate::models::model_params::FileGenerationParams; 3 | use std::fs; 4 | use std::io; 5 | 6 | /// Generates files for a new Rust project based on a YAML file. 7 | /// 8 | /// The YAML file must contain a single object with the following 9 | /// properties: 10 | /// 11 | /// - `author` - the author of the project (optional). 12 | /// - `build` - the build command to be used for building the project (optional). 13 | /// - `categories` - the categories that the project belongs to (optional). 14 | /// - `description` - a short description of the project (optional). 15 | /// - `documentation` - the documentation URL of the project (optional). 16 | /// - `edition` - the edition of the project (optional). 17 | /// - `email` - the email address of the author (optional). 18 | /// - `homepage` - the homepage of the project (optional). 19 | /// - `keywords` - keywords that describe the project (optional). 20 | /// - `license` - the license under which the project is released (optional). 21 | /// - `name` - the name of the project (optional). 22 | /// - `output` - the output directory where the project files will be created (required). 23 | /// - `readme` - the name of the readme file (optional). 24 | /// - `repository` - the url of the project's repository (optional). 25 | /// - `rustversion` - the minimum Rust version required by the project (optional). 26 | /// - `version` - the initial version of the project (optional). 27 | /// - `website` - the website of the project (optional). 28 | /// 29 | /// # Errors 30 | /// 31 | /// This function will return an error in the following situations: 32 | /// 33 | /// - If the specified YAML file cannot be found, read, or is not valid UTF-8. 34 | /// - If the YAML data cannot be deserialized into the `FileGenerationParams` struct. 35 | /// - If there is an error in generating files based on the parameters. 36 | /// 37 | pub fn generate_from_yaml(path: &str) -> io::Result<()> { 38 | let contents = fs::read_to_string(path)?; 39 | let params: FileGenerationParams = 40 | serde_yml::from_str(&contents) 41 | .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; 42 | macro_generate_files!(params.clone()) 43 | .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; 44 | Ok(()) 45 | } 46 | -------------------------------------------------------------------------------- /src/interface.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | use crate::macro_replace_placeholder; 7 | use crate::models::model_params::FileGenerationParams; 8 | use std::{ 9 | fs::File, 10 | io::{BufRead, BufReader, Write}, 11 | path::PathBuf, 12 | }; 13 | 14 | /// Replaces placeholders in a template file with values from the provided parameters 15 | /// and writes the result to an output file. 16 | /// 17 | /// # Arguments 18 | /// 19 | /// * `template_file` - Path to the template file. 20 | /// * `output_file` - Path to the output file where the result should be written. 21 | /// * `params` - Parameters containing values to replace placeholders in the template. 22 | /// 23 | /// # Errors 24 | /// 25 | /// Returns an `std::io::Result` error if: 26 | /// 27 | /// - The template file cannot be read. 28 | /// - The output file cannot be created or written to. 29 | /// - There are issues parsing the template or replacing placeholders. 30 | /// 31 | pub fn replace_placeholders( 32 | template_file: &PathBuf, 33 | output_file: &PathBuf, 34 | params: &FileGenerationParams, 35 | ) -> std::io::Result<()> { 36 | let tpl = File::open(template_file)?; 37 | let tpl_reader = BufReader::new(tpl); 38 | let mut output = File::create(output_file)?; 39 | let tpl_lines = tpl_reader.lines(); 40 | 41 | for line in tpl_lines { 42 | let line = line?; 43 | let replaced_line = macro_replace_placeholder!( 44 | line, 45 | params, 46 | author, 47 | build, 48 | categories, 49 | description, 50 | documentation, 51 | edition, 52 | email, 53 | homepage, 54 | keywords, 55 | license, 56 | name, 57 | output, 58 | readme, 59 | repository, 60 | rustversion, 61 | version, 62 | website 63 | ); 64 | writeln!(output, "{replaced_line}")?; 65 | } 66 | 67 | Ok(()) 68 | } 69 | -------------------------------------------------------------------------------- /src/macros/ascii_macros.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | /// A macro for generating ASCII art from text. 7 | /// 8 | /// This macro takes a string literal as input and generates ASCII art using the `generate_ascii_art` function. 9 | /// If the conversion is successful, the macro returns the ASCII art as a string. 10 | /// If an error occurs during the conversion, the macro panics with an error message. 11 | /// 12 | /// # Examples 13 | /// 14 | /// ``` 15 | /// use libmake::macro_ascii; 16 | /// 17 | /// let art = macro_ascii!("Hello, world!"); 18 | /// println!("{}", art); 19 | /// ``` 20 | #[macro_export] 21 | macro_rules! macro_ascii { 22 | ($text:expr) => { 23 | match $crate::generators::ascii::generate_ascii_art($text) { 24 | Ok(art) => art, 25 | Err(err) => panic!("Failed to generate ASCII art: {}", err), 26 | } 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /src/macros/file_macros.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | /// Macro to simplify the match logic for file generation. 7 | #[macro_export] 8 | macro_rules! generate_file { 9 | ($file_type:expr, $value:expr, $generator:expr) => { 10 | if !$value.trim().is_empty() { 11 | if let Err(err) = $generator($value) { 12 | eprintln!( 13 | "Error generating {} file: {}", 14 | $file_type, err 15 | ); 16 | } 17 | } 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /src/macros/log_macros.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | //! This module contains macros related to logging messages at various log levels and formats. 7 | //! 8 | //! It includes a custom logging macro, `macro_log_info`, which allows logging messages with 9 | //! specified log levels, components, descriptions, and formats. 10 | //! 11 | //! # Custom Logging Macro 12 | //! 13 | //! The `macro_log_info` macro is designed for logging messages with customizable log levels, 14 | //! components, descriptions, and formats. It provides flexibility in defining log messages 15 | //! according to specific requirements. 16 | //! 17 | //! # Parameters 18 | //! 19 | //! - `$level`: The log level of the message. 20 | //! - `$component`: The component where the log is coming from. 21 | //! - `$description`: A description of the log message. 22 | //! - `$format`: The format of the log message. 23 | //! 24 | 25 | /// Custom logging macro for various log levels and formats. 26 | /// 27 | /// # Parameters 28 | /// 29 | /// * `$level`: The log level of the message. 30 | /// * `$component`: The component where the log is coming from. 31 | /// * `$description`: A description of the log message. 32 | /// * `$format`: The format of the log message. 33 | /// 34 | #[macro_export] 35 | macro_rules! macro_log_info { 36 | ($level:expr, $component:expr, $description:expr, $format:expr) => {{ 37 | // Get the current date and time in ISO 8601 format. 38 | let date = DateTime::new(); // Create a new DateTime instance 39 | let iso = date.iso_8601; // Get ISO 8601 formatted date and time 40 | 41 | // Create a new random number generator 42 | let mut rng = Random::default(); // Default random number generator 43 | let session_id = rng.rand().to_string(); // Generate session ID 44 | 45 | // Create a new log instance 46 | let log = Log::new( 47 | &session_id, // Session ID 48 | &iso, // ISO 8601 formatted date and time 49 | $level, // Log level 50 | $component, // Component name 51 | $description, // Log description 52 | $format, // Log format 53 | ); 54 | log // Return the Log instance 55 | }}; 56 | } 57 | -------------------------------------------------------------------------------- /src/macros/mod.rs: -------------------------------------------------------------------------------- 1 | /// A macro for generating ASCII art from text. 2 | pub mod ascii_macros; 3 | 4 | /// The `directory_macros` module contains macros related to directory 5 | /// operations. 6 | pub mod directory_macros; 7 | 8 | /// The `file_macros` module contains macros related to file operations. 9 | pub mod file_macros; 10 | 11 | /// The `generator_macros` module contains macros related to generating 12 | /// templates from JSON, YAML, and CSV files, and custom logging functionality. 13 | pub mod generator_macros; 14 | 15 | /// The `log_macros` module contains macros related to logging messages at various log levels and formats. 16 | pub mod log_macros; 17 | 18 | /// The `utility_macros` module contains utility macros for common tasks such as 19 | /// replacing placeholders in a line with values from parameters. 20 | pub mod utility_macros; 21 | -------------------------------------------------------------------------------- /src/macros/utility_macros.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | /// Replaces placeholders in a given line with corresponding values from the provided parameters. 7 | /// 8 | /// # Arguments 9 | /// 10 | /// * `line` - The line containing placeholders to be replaced. 11 | /// * `params` - The parameters containing values to replace the placeholders. 12 | /// * `$($field:ident),+` - Identifiers representing the fields in `params` to be replaced. 13 | /// 14 | /// # Returns 15 | /// 16 | /// The line with placeholders replaced by their corresponding values. 17 | /// 18 | #[macro_export] 19 | macro_rules! macro_replace_placeholder { 20 | ($line:expr, $params:expr, $($field:ident),+) => { 21 | { 22 | let mut line = $line; 23 | $( 24 | line = line.replace( 25 | concat!("{", stringify!($field), "}"), 26 | &$params.$field.as_deref().unwrap_or(""), 27 | ); 28 | )+ 29 | line 30 | } 31 | }; 32 | } 33 | 34 | /// Macro to generate a function that retrieves a field value from a JSON file. 35 | /// 36 | /// # Arguments 37 | /// 38 | /// * `$func_name` - The name of the generated function. 39 | /// * `$deserializer` - The deserializer used to parse the JSON file. 40 | /// 41 | /// # Returns 42 | /// 43 | /// The generated function returns a `Result` containing the field value as a `String`, 44 | /// or a `Box` if an error occurs. 45 | /// 46 | #[macro_export] 47 | macro_rules! macro_get_field { 48 | ($func_name:ident, $deserializer:expr) => { 49 | /// Reads a file and deserializes its content using the specified 50 | /// deserializer function. 51 | pub fn $func_name( 52 | // The path of the JSON file to read. 53 | file_path: Option<&str>, 54 | // The name of the field to retrieve. 55 | field_name: &str, 56 | ) -> Result> { 57 | file_path.map_or_else( 58 | || Ok(String::new()), 59 | |file_path| { 60 | let current_dir = env::current_dir()?; 61 | let file_path = 62 | Path::new(¤t_dir).join(file_path); 63 | read_file(&file_path, |file| { 64 | let value: serde_json::Value = 65 | $deserializer(file)?; 66 | let field_value = value 67 | .get(field_name) 68 | .ok_or_else(|| { 69 | format!( 70 | "Field '{}' not found", 71 | field_name 72 | ) 73 | })? 74 | .as_str() 75 | .map(|s| s.to_string()) 76 | .unwrap_or_else(|| { 77 | value[field_name].to_string() 78 | }); 79 | Ok(field_value) 80 | }) 81 | }, 82 | ) 83 | } 84 | }; 85 | } 86 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | //! # Libmake Application 7 | //! 8 | //! This is the main entry point for the cmn application. 9 | //! Call the `run()` function from the `LibMake (LM)` module. 10 | //! 11 | //! # Purpose 12 | //! The purpose of this function is to serve as the entry point for the `cmn` application. 13 | //! It calls the `run` function from the `LibMake (LM)` crate to execute the desired tasks. 14 | //! 15 | //! # Usage 16 | //! To use the `cmn` application, you can include it as part of your Rust project. 17 | //! The `main` function of the application calls the `run` function from the `LibMake (LM)` module. 18 | //! If an error occurs during execution, it prints an error message and exits with a non-zero status code. 19 | //! 20 | //! ```rust 21 | //! use libmake::run; 22 | //! 23 | //!/ This is the main entry point for the cmn application. 24 | //! Call the `run()` function from the `LibMake (LM)` module. 25 | //! if let Err(ref e) = run() { 26 | //! eprintln!("Error running cmn: {}", e); 27 | //! std::process::exit(1); 28 | //! } 29 | //! ``` 30 | //! 31 | //! This application allows you to interact with and use the functionality provided by the `LibMake (LM)` crate. 32 | 33 | use libmake::run; 34 | 35 | /// This is the main entry point for the cmn application. 36 | /// Call the `run()` function from the `LibMake (LM)` module. 37 | /// 38 | /// # Parameters 39 | /// This function does not take any parameters. 40 | /// 41 | /// # Returns 42 | /// This function returns a `Result` type. If the `run` function from the `LibMake (LM)` module succeeds, it returns `Ok(())`. If an error occurs, it returns `Err(err)`, where `err` is an instance of the `Error` type. 43 | /// 44 | /// # Panics 45 | /// This function may panic if the `run` function from the `LibMake (LM)` module returns an error and the error is not handled properly. 46 | /// 47 | /// # Examples 48 | /// ```rust 49 | /// use libmake::run; 50 | /// 51 | /// This is the main entry point for the cmn application. 52 | /// Call the `run()` function from the `LibMake (LM)` module. 53 | /// if let Err(err) = run() { 54 | /// eprintln!("Error running cmn: {}", err); 55 | /// std::process::exit(1); 56 | /// } 57 | /// ``` 58 | /// 59 | /// # See Also 60 | /// - [`run` function from the `LibMake (LM)` module](crate::libmake::run) 61 | /// 62 | /// # Author 63 | /// Copyright © 2023-2024 LibMake. All rights reserved. 64 | /// 65 | /// # License 66 | /// This code is dual-licensed under the Apache License 2.0 and the MIT License. 67 | 68 | fn main() { 69 | // Call the `run()` function from the `LibMake (LM)` module. 70 | if let Err(err) = run() { 71 | eprintln!("Error running cmn: {}", err); 72 | std::process::exit(1); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/models/error_ascii_art.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | use std::error::Error; 7 | use std::fmt; 8 | 9 | /// Error type for ASCII art generation failures. 10 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] 11 | pub enum AsciiArtError { 12 | /// Represents a failure to load the FIGfont. 13 | FontLoadError, 14 | /// Represents a failure to convert text to ASCII art. 15 | ConversionError, 16 | } 17 | 18 | impl fmt::Display for AsciiArtError { 19 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 20 | match *self { 21 | Self::FontLoadError => write!(f, "Failed to load FIGfont"), 22 | Self::ConversionError => { 23 | write!(f, "Failed to convert text to ASCII art") 24 | } 25 | } 26 | } 27 | } 28 | 29 | impl Error for AsciiArtError { 30 | fn source(&self) -> Option<&(dyn Error + 'static)> { 31 | None 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/models/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | /// The `ascii_art_error` module contains the `AsciiArtError` type for ASCII art generation failures. 7 | pub mod error_ascii_art; 8 | 9 | /// The `model_params` module contains the `FileGenerationParams` type for holding the parameters for generating the project files. 10 | pub mod model_params; 11 | -------------------------------------------------------------------------------- /src/utilities/directory.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | use std::{ 7 | error::Error, 8 | fs::{self}, 9 | path::{Path, PathBuf}, 10 | }; 11 | /// Ensures a directory exists, creating it if necessary. 12 | /// 13 | /// This function takes a reference to a `Path` object for a directory and a 14 | /// human-readable name for the directory, and creates the directory if it 15 | /// does not already exist. 16 | /// 17 | /// # Arguments 18 | /// 19 | /// * `dir` - A reference to a `Path` object for the directory. 20 | /// * `name` - A human-readable name for the directory, used in error messages. 21 | /// 22 | /// # Returns 23 | /// 24 | /// * `Result<(), String>` - A result indicating success or failure. 25 | /// - `Ok(())` if the directory exists or was created successfully. 26 | /// - `Err(String)` if the directory does not exist and could not be created. 27 | /// 28 | /// # Example 29 | /// 30 | /// ``` 31 | /// use libmake::utilities::directory::directory; 32 | /// use std::path::Path; 33 | /// use std::fs; 34 | /// 35 | /// // Create a "logs" directory if it doesn't exist 36 | /// let dir = Path::new("logs"); 37 | /// directory(dir, "logs").expect("Could not create logs directory"); 38 | /// fs::remove_dir_all(dir).expect("Could not remove logs directory"); 39 | /// ``` 40 | /// 41 | pub fn directory(dir: &Path, name: &str) -> Result { 42 | if dir.exists() { 43 | if !dir.is_dir() { 44 | return Err(format!( 45 | "❌ Error: {} is not a directory.", 46 | name 47 | )); 48 | } 49 | } else { 50 | match fs::create_dir_all(dir) { 51 | Ok(_) => {} 52 | Err(e) => { 53 | return Err(format!( 54 | "❌ Error: Cannot create {} directory: {}", 55 | name, e 56 | )) 57 | } 58 | } 59 | } 60 | Ok(String::new()) 61 | } 62 | 63 | /// Moves the output directory to the public directory. 64 | /// 65 | /// This function takes a reference to a `Path` object for the output directory 66 | /// and a string for the site name, and moves the output directory to the 67 | /// public directory. 68 | /// 69 | /// # Arguments 70 | /// 71 | /// * `site_name` - A string for the site name. 72 | /// * `out_dir` - A reference to a `Path` object for the output directory. 73 | /// 74 | /// # Returns 75 | /// 76 | /// * `Result<(), std::io::Error>` - A result indicating success or failure. 77 | /// - `Ok(())` if the output directory was moved successfully. 78 | /// - `Err(std::io::Error)` if the output directory could not be moved. 79 | /// 80 | pub fn move_output_directory( 81 | site_name: &str, 82 | out_dir: &Path, 83 | ) -> std::io::Result<()> { 84 | println!("❯ Moving output directory..."); 85 | 86 | let public_dir = Path::new("public"); 87 | 88 | if public_dir.exists() { 89 | fs::remove_dir_all(public_dir)?; 90 | } 91 | 92 | fs::create_dir(public_dir)?; 93 | 94 | let site_name = site_name.replace(' ', "_"); 95 | let new_project_dir = public_dir.join(site_name); 96 | fs::create_dir_all(&new_project_dir)?; 97 | 98 | fs::rename(out_dir, &new_project_dir)?; 99 | 100 | println!(" Done.\n"); 101 | 102 | Ok(()) 103 | } 104 | 105 | /// Cleans up the directory at the given path. 106 | /// 107 | /// If the directory does not exist, this function does nothing. 108 | /// 109 | /// # Arguments 110 | /// 111 | /// * `directories` - An array of references to `Path` objects representing the 112 | /// directories to be cleaned up. 113 | /// 114 | /// # Returns 115 | /// 116 | /// * `Result<(), Box>` - A result indicating success or failure. 117 | /// - `Ok(())` if the directories were cleaned up successfully. 118 | /// - `Err(Box)` if an error occurred during the cleanup process. 119 | /// 120 | pub fn cleanup_directory( 121 | directories: &[&Path], 122 | ) -> Result<(), Box> { 123 | for directory in directories { 124 | if !directory.exists() { 125 | continue; 126 | } 127 | 128 | println!("\n❯ Cleaning up directories"); 129 | 130 | fs::remove_dir_all(directory)?; 131 | 132 | println!(" Done.\n"); 133 | } 134 | 135 | Ok(()) 136 | } 137 | 138 | /// Creates a new directory at the given path. 139 | /// 140 | /// If the directory already exists, this function does nothing. 141 | /// 142 | /// # Arguments 143 | /// 144 | /// * `directories` - An array of references to `Path` objects representing the 145 | /// directories to be created. 146 | /// 147 | /// # Returns 148 | /// 149 | /// * `Result<(), Box>` - A result indicating success or failure. 150 | /// - `Ok(())` if the directories were created successfully. 151 | /// - `Err(Box)` if an error occurred during the creation process. 152 | /// 153 | pub fn create_directory( 154 | directories: &[&Path], 155 | ) -> Result<(), Box> { 156 | for directory in directories { 157 | if directory.exists() { 158 | continue; 159 | } 160 | 161 | fs::create_dir(directory)?; 162 | } 163 | 164 | Ok(()) 165 | } 166 | 167 | /// Truncates a path to only have a set number of path components. 168 | /// 169 | /// Will truncate a path to only show the last `length` components in a path. 170 | /// If a length of `0` is provided, the path will not be truncated. 171 | /// A value will only be returned if the path has been truncated. 172 | /// 173 | /// # Arguments 174 | /// 175 | /// * `path` - The path to truncate. 176 | /// * `length` - The number of path components to keep. 177 | /// 178 | /// # Returns 179 | /// 180 | /// * An `Option` of the truncated path as a string. If the path was not truncated, `None` is returned. 181 | pub fn truncate(path: &Path, length: usize) -> Option { 182 | // Checks if the length is 0. If it is, returns `None`. 183 | if length == 0 { 184 | return None; 185 | } 186 | 187 | // Creates a new PathBuf object to store the truncated path. 188 | let mut truncated = PathBuf::new(); 189 | 190 | // Iterates over the components of the path in reverse order. 191 | let mut count = 0; 192 | while let Some(component) = path.components().next_back() { 193 | // Adds the component to the truncated path. 194 | truncated.push(component); 195 | count += 1; 196 | 197 | // If the count reaches the desired length, breaks out of the loop. 198 | if count == length { 199 | break; 200 | } 201 | } 202 | 203 | // If the count is equal to the desired length, returns the truncated path as a string. 204 | if count == length { 205 | Some(truncated.to_string_lossy().to_string()) 206 | } else { 207 | // Otherwise, returns `None`. 208 | None 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /src/utilities/mod.rs: -------------------------------------------------------------------------------- 1 | /// The `directory` module contains functions related to directory operations. 2 | pub mod directory; 3 | 4 | /// The `uuid` module contains functions related to generating UUIDs. 5 | pub mod uuid; 6 | -------------------------------------------------------------------------------- /src/utilities/uuid.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | // Import the Uuid type from the uuid crate 7 | use uuid::Uuid; 8 | 9 | /// Generates a unique string. 10 | /// 11 | /// This function generates a new unique string using UUID version 4 (random). 12 | /// 13 | /// # Returns 14 | /// 15 | /// A string containing the generated unique identifier. 16 | /// 17 | /// # Examples 18 | /// 19 | /// ``` 20 | /// use libmake::utilities::uuid::generate_unique_string; 21 | /// 22 | /// let unique_string = generate_unique_string(); 23 | /// println!("Unique string: {}", unique_string); 24 | /// ``` 25 | pub fn generate_unique_string() -> String { 26 | // Generate a new UUID v4 (random) and convert it to a string 27 | Uuid::new_v4().to_string() 28 | } 29 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | use crate::macro_get_field; 7 | use std::{ 8 | env, 9 | fs::{self, File}, 10 | io, 11 | path::Path, 12 | }; 13 | 14 | /// Reads a file and deserializes its content using the specified deserializer function. 15 | /// 16 | /// # Arguments 17 | /// 18 | /// * `file_path` - The path of the file to read. 19 | /// * `deserializer` - A function that takes a `File` and returns a deserialized value of type `T`. 20 | /// 21 | /// # Returns 22 | /// 23 | /// Returns a `Result>` containing the deserialized value, or an error if one occurs. 24 | /// 25 | fn read_file( 26 | file_path: &Path, 27 | deserializer: F, 28 | ) -> Result> 29 | where 30 | F: FnOnce(File) -> Result>, 31 | { 32 | let file = File::open(file_path)?; 33 | deserializer(file) 34 | } 35 | 36 | /// Reads a CSV file at the given file path and returns the value of 37 | /// the given field. 38 | /// 39 | /// # Arguments 40 | /// 41 | /// * `file_path` - An optional string slice that holds the file path of the CSV file to read. 42 | /// * `field_index` - The index of the field to retrieve. 43 | /// 44 | pub fn get_csv_field( 45 | file_path: Option<&str>, 46 | field_index: usize, 47 | ) -> Option> { 48 | file_path.and_then(|file_path| { 49 | let current_dir = env::current_dir().ok()?; 50 | let file_path = Path::new(¤t_dir).join(file_path); 51 | let file = File::open(file_path).ok()?; 52 | let mut rdr = csv::Reader::from_reader(file); 53 | 54 | let mut values = Vec::new(); 55 | for result in rdr.records() { 56 | let record = result.ok()?; 57 | if let Some(field_value) = record.get(field_index) { 58 | values.push(field_value.to_string()); 59 | } else { 60 | // Field index is out of range 61 | return None; 62 | } 63 | } 64 | if values.is_empty() { 65 | None 66 | } else { 67 | Some(values) 68 | } 69 | }) 70 | } 71 | 72 | macro_get_field!(get_ini_field, serde_ini::from_read); 73 | macro_get_field!(get_json_field, serde_json::from_reader); 74 | macro_get_field!(get_yaml_field, serde_yml::from_reader); 75 | 76 | /// Retrieves a specific field's value from a configuration file. 77 | /// 78 | /// # Arguments 79 | /// 80 | /// * `file_path` - An optional reference to the path of the configuration file. 81 | /// * `file_format` - The format of the configuration file ("json", "yaml", or "ini"). 82 | /// * `field_name` - The name of the field to retrieve the value from. 83 | /// 84 | /// # Returns 85 | /// 86 | /// Returns a `Result>` containing the value of the specified field, or an error if one occurs. 87 | /// 88 | pub fn get_config_field( 89 | file_path: Option<&str>, 90 | file_format: Option<&str>, 91 | field_name: &str, 92 | ) -> Result> { 93 | // Ensure file_path is provided 94 | let file_path = file_path.ok_or("File path is not provided")?; 95 | 96 | // Ensure file_format is provided and is either 'json', 'yaml', or 'ini' 97 | let format = file_format.ok_or("File format is not provided")?; 98 | match format { 99 | "ini" => get_ini_field(Some(file_path), field_name), 100 | "json" => get_json_field(Some(file_path), field_name), 101 | "yaml" => get_yaml_field(Some(file_path), field_name), 102 | _ => Err(format!( 103 | "Unsupported file format: {}. Supported formats are 'json', 'yaml', and 'ini'.", 104 | format 105 | ) 106 | .into()), 107 | } 108 | } 109 | 110 | /// Creates a directory at the specified path. 111 | /// 112 | /// # Arguments 113 | /// 114 | /// * `path` - The path where the directory should be created. 115 | /// 116 | /// # Errors 117 | /// 118 | /// Returns an `io::Error` if the directory cannot be created. This could be due to 119 | /// various reasons such as insufficient permissions, the directory already existing, 120 | /// or other I/O-related errors. 121 | /// 122 | pub fn create_directory(path: &Path) -> io::Result<()> { 123 | fs::create_dir(path).or_else(|e| match e.kind() { 124 | io::ErrorKind::AlreadyExists => Ok(()), 125 | _ => Err(e), 126 | }) 127 | } 128 | -------------------------------------------------------------------------------- /template/AUTHORS.tpl: -------------------------------------------------------------------------------- 1 | # Authors 2 | 3 | * {author} ({email}) (Original Contributor) 4 | -------------------------------------------------------------------------------- /template/CONTRIBUTING.tpl: -------------------------------------------------------------------------------- 1 | # Contributing to `{name}` 2 | 3 | Welcome! We're thrilled that you're interested in contributing to the 4 | `{name}` library. Whether you're looking to evangelize, submit feedback, 5 | or contribute code, we appreciate your involvement in making `{name}` a 6 | better tool for everyone. Here's how you can get started. 7 | 8 | ## Evangelize 9 | 10 | One of the simplest ways to help us out is by spreading the word about 11 | {name}. We believe that a bigger, more involved community makes for a 12 | better framework, and that better frameworks make the world a better 13 | place. If you know people who might benefit from using {name}, please 14 | let them know! 15 | 16 | ## How to Contribute 17 | 18 | If you're interested in making a more direct contribution, there are 19 | several ways you can help us improve {name}. Here are some guidelines 20 | for submitting feedback, bug reports, and code contributions. 21 | 22 | ### Feedback 23 | 24 | Your feedback is incredibly valuable to us, and we're always looking for 25 | ways to make {name} better. If you have ideas, suggestions, or questions 26 | about {name}, we'd love to hear them. Here's how you can provide 27 | feedback: 28 | 29 | - Click [here][2] to submit a new feedback. 30 | - Use a descriptive title that clearly summarizes your feedback. 31 | - Provide a detailed description of the issue or suggestion. 32 | - Be patient while we review and respond to your feedback. 33 | 34 | ### Bug Reports 35 | 36 | If you encounter a bug while using {name}, please let us know so we can 37 | fix it. Here's how you can submit a bug report: 38 | 39 | - Click [here][2] to submit a new issue. 40 | - Use a descriptive title that clearly summarizes the bug. 41 | - Provide a detailed description of the issue, including steps to 42 | reproduce it. 43 | - Be patient while we review and respond to your bug report. 44 | 45 | ### Code Contributions 46 | 47 | If you're interested in contributing code to {name}, we're excited to 48 | have your help! Here's what you need to know: 49 | 50 | #### Feature Requests 51 | 52 | If you have an idea for a new feature or improvement, we'd love to hear 53 | it. Here's how you can contribute code for a new feature to {name}: 54 | 55 | - Fork the repo. 56 | - Clone the {name}[1] repo by running: 57 | `git clone {repository}` 58 | - Edit files in the `src/` folder. The `src/` folder contains the source 59 | code for {name}. 60 | - Submit a pull request, and we'll review and merge your changes if they 61 | fit with our vision for {name}. 62 | 63 | #### Submitting Code 64 | 65 | If you've identified a bug or have a specific code improvement in mind, 66 | we welcome your pull requests. Here's how to submit your code changes: 67 | 68 | - Fork the repo. 69 | - Clone the {name} repo by running: 70 | `git clone {repository}` 71 | - Edit files in the `src/` folder. The `src/` folder contains the source 72 | code for {name}. 73 | - Submit a pull request, and we'll review and merge your changes if they 74 | fit with our vision for {name}. 75 | 76 | We hope that this guide has been helpful in explaining how you can 77 | contribute to {name}. Thank you for your interest and involvement in our 78 | project! 79 | 80 | [1]: {repository} 81 | [2]: {repository}/issues/new 82 | -------------------------------------------------------------------------------- /template/Cargo.tpl: -------------------------------------------------------------------------------- 1 | [package] 2 | # Metadata about the package. 3 | authors = "{author}" 4 | build = "{build}" 5 | categories = [{categories}] 6 | description = "{description}" 7 | documentation = "{documentation}" 8 | edition = "{edition}" 9 | exclude = ["/.git/*", "/.github/*", "/.gitignore", "/.vscode/*"] 10 | homepage = "{homepage}" 11 | keywords = [{keywords}] 12 | license = "{license}" 13 | name = "{name}" 14 | readme = "{readme}" 15 | repository = "{repository}" 16 | rust-version = "{rustversion}" 17 | version = "{version}" 18 | include = [ 19 | "/CONTRIBUTING.md", 20 | "/LICENSE-APACHE", 21 | "/LICENSE-MIT", 22 | "/benches/**", 23 | "/build.rs", 24 | "/Cargo.toml", 25 | "/examples/**", 26 | "/README.md", 27 | "/src/**", 28 | "/tests/**" 29 | ] 30 | 31 | [[bench]] 32 | # Benchmarking configuration. 33 | name = "benchmark" 34 | harness = false 35 | path = "benches/criterion.rs" 36 | 37 | [profile.bench] 38 | debug = true 39 | 40 | [dependencies] 41 | # The dependencies of the package. 42 | anyhow = "1.0.83" 43 | dtt = "0.0.6" 44 | env_logger = "0.11.3" 45 | rlg = "0.0.4" 46 | serde = { version = "1.0.201", features = ["derive"] } 47 | serde_json = "1.0.117" 48 | serde_yml = "0.0.5" 49 | toml = "0.8.12" 50 | vrd = "0.0.7" 51 | 52 | [dev-dependencies] 53 | # The development dependencies of the package. 54 | criterion = "0.5.1" 55 | 56 | [lib] 57 | # The library configuration. 58 | crate-type = ["lib"] 59 | name = "{name}" 60 | path = "src/lib.rs" 61 | 62 | [features] 63 | # The features of the package. 64 | default = [] 65 | 66 | [package.metadata.docs.rs] 67 | # Configuration for docs.rs. 68 | targets = ["x86_64-unknown-linux-gnu"] 69 | rustdoc-args = ["--generate-link-to-definition"] 70 | 71 | # Linting config 72 | [lints.rust] 73 | 74 | ## Warn 75 | missing_copy_implementations = "warn" 76 | missing_docs = "warn" 77 | unstable_features = "warn" 78 | unused_extern_crates = "warn" 79 | unused_results = "warn" 80 | 81 | ## Allow 82 | bare_trait_objects = "allow" 83 | elided_lifetimes_in_paths = "allow" 84 | non_camel_case_types = "allow" 85 | non_upper_case_globals = "allow" 86 | trivial_bounds = "allow" 87 | unsafe_code = "allow" 88 | 89 | ## Forbid 90 | missing_debug_implementations = "forbid" 91 | non_ascii_idents = "forbid" 92 | unreachable_pub = "forbid" 93 | 94 | ## Deny 95 | dead_code = "deny" 96 | deprecated_in_future = "deny" 97 | ellipsis_inclusive_range_patterns = "deny" 98 | explicit_outlives_requirements = "deny" 99 | future_incompatible = { level = "deny", priority = -1 } 100 | keyword_idents = "deny" 101 | macro_use_extern_crate = "deny" 102 | meta_variable_misuse = "deny" 103 | missing_fragment_specifier = "deny" 104 | noop_method_call = "deny" 105 | pointer_structural_match = "deny" 106 | rust_2018_idioms = { level = "deny", priority = -1 } 107 | rust_2021_compatibility = { level = "deny", priority = -1 } 108 | single_use_lifetimes = "deny" 109 | trivial_casts = "deny" 110 | trivial_numeric_casts = "deny" 111 | unused = { level = "deny", priority = -1 } 112 | unused_features = "deny" 113 | unused_import_braces = "deny" 114 | unused_labels = "deny" 115 | unused_lifetimes = "deny" 116 | unused_macro_rules = "deny" 117 | unused_qualifications = "deny" 118 | variant_size_differences = "deny" 119 | 120 | [package.metadata.clippy] 121 | # Clippy configuration. 122 | warn-lints = ["clippy::all", "clippy::pedantic", "clippy::cargo", "clippy::nursery"] 123 | 124 | [profile.dev] 125 | # Development profile configuration. 126 | codegen-units = 256 127 | debug = true 128 | debug-assertions = true 129 | incremental = true 130 | lto = false 131 | opt-level = 0 132 | overflow-checks = true 133 | panic = 'unwind' 134 | rpath = false 135 | strip = false 136 | 137 | [profile.release] 138 | # Release profile configuration. 139 | codegen-units = 1 140 | debug = false 141 | debug-assertions = false 142 | incremental = false 143 | lto = true 144 | opt-level = "s" 145 | overflow-checks = false 146 | panic = 'abort' 147 | rpath = false 148 | strip = 'symbols' 149 | 150 | [profile.test] 151 | # Test profile configuration. 152 | codegen-units = 256 153 | debug = true 154 | debug-assertions = true 155 | incremental = true 156 | lto = false 157 | opt-level = 0 158 | overflow-checks = true 159 | rpath = false 160 | strip = false 161 | -------------------------------------------------------------------------------- /template/README.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | {name}'s logo 10 | 11 | 12 | 13 | # {name} 14 | 15 | {description} 16 | 17 | 18 |
19 | 20 | 21 | [![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] 22 | 23 | • [Website][00] • [Documentation][07] • [Report Bug][02] • [Request Feature][02] • [Contributing Guidelines][03] 24 | 25 | 26 |
27 | 28 | 29 | ![divider][divider] 30 | 31 | ## Overview 📖 32 | 33 | {description} 34 | 35 | ## Features ✨ 36 | 37 | - Feature 1 38 | - Feature 2 39 | - Feature 3 40 | 41 | ## Getting Started 🚀 42 | 43 | It takes just a few minutes to get up and running with `{name}`. 44 | 45 | ### Installation 46 | 47 | To install `{name}`, you need to have the Rust toolchain installed on 48 | your machine. You can install the Rust toolchain by following the 49 | instructions on the [Rust website][12]. 50 | 51 | Once you have the Rust toolchain installed, you can install `{name}` 52 | using the following command: 53 | 54 | ```shell 55 | cargo install {name} 56 | ``` 57 | 58 | ### Requirements 59 | 60 | The minimum supported Rust toolchain version is currently Rust 61 | **{rustversion}** or later (stable). 62 | 63 | ### Platform support 64 | 65 | `{name}` is supported and tested on the following platforms: 66 | 67 | ### Tier 1 platforms 🏆 68 | 69 | | | Operating System | Target | Description | 70 | | --- | --- | --- | --- | 71 | | ✅ | Linux | aarch64-unknown-linux-gnu | 64-bit Linux systems on ARM architecture | 72 | | ✅ | Linux | i686-unknown-linux-gnu | 32-bit Linux (kernel 3.2+, glibc 2.17+) | 73 | | ✅ | Linux | x86_64-unknown-linux-gnu | 64-bit Linux (kernel 2.6.32+, glibc 2.11+) | 74 | | ✅ | macOS | x86_64-apple-darwin | 64-bit macOS (10.7 Lion or later) | 75 | | ✅ | Windows | i686-pc-windows-gnu | 32-bit Windows (7 or later) | 76 | | ✅ | Windows | i686-pc-windows-msvc | 32-bit Windows (7 or later) | 77 | | ✅ | Windows | x86_64-pc-windows-gnu | 64-bit Windows (7 or later) | 78 | | ✅ | Windows | x86_64-pc-windows-msvc | 64-bit Windows (7 or later) | 79 | 80 | ### Tier 2 platforms 🥈 81 | 82 | | | Operating System | Target | Description | 83 | | --- | --- | --- | --- | 84 | | ✅ | Linux | aarch64-unknown-linux-musl | 64-bit Linux systems on ARM architecture | 85 | | ✅ | Linux | arm-unknown-linux-gnueabi | ARMv6 Linux (kernel 3.2, glibc 2.17) | 86 | | ✅ | Linux | arm-unknown-linux-gnueabihf | ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17) | 87 | | ✅ | Linux | armv7-unknown-linux-gnueabihf | ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17) | 88 | | ✅ | Linux | mips-unknown-linux-gnu | MIPS Linux (kernel 2.6.32+, glibc 2.11+) | 89 | | ✅ | Linux | mips64-unknown-linux-gnuabi64 | MIPS64 Linux (kernel 2.6.32+, glibc 2.11+) | 90 | | ✅ | Linux | mips64el-unknown-linux-gnuabi64 | MIPS64 Linux (kernel 2.6.32+, glibc 2.11+) | 91 | | ✅ | Linux | mipsel-unknown-linux-gnu | MIPS Linux (kernel 2.6.32+, glibc 2.11+) | 92 | | ✅ | macOS | aarch64-apple-darwin | 64-bit macOS (10.7 Lion or later) | 93 | | ✅ | Windows | aarch64-pc-windows-msvc | 64-bit Windows (7 or later) | 94 | 95 | The [GitHub Actions][09] shows the platforms in which the `{name}` 96 | library tests are run. 97 | 98 | ### Documentation 99 | 100 | **Info:** Please check out our [website][00] for more information. You can find our documentation on [docs.rs][07], [lib.rs][08] and 101 | [crates.io][06]. 102 | 103 | ## Usage 📖 104 | 105 | To use the `{name}` library in your project, add the following to your 106 | `Cargo.toml` file: 107 | 108 | ```toml 109 | [dependencies] 110 | {name} = {version} 111 | ``` 112 | 113 | Add the following to your `main.rs` file: 114 | 115 | ```rust 116 | extern crate {name}; 117 | use {name}::*; 118 | ``` 119 | 120 | then you can use the functions in your application code. 121 | 122 | ### Examples 123 | 124 | To get started with `{name}`, you can use the examples provided in the 125 | `examples` directory of the project. 126 | 127 | To run the examples, clone the repository and run the following command 128 | in your terminal from the project root directory. 129 | 130 | ```shell 131 | cargo run --example example 132 | ``` 133 | 134 | ## Semantic Versioning Policy 🚥 135 | 136 | For transparency into our release cycle and in striving to maintain 137 | backward compatibility, `{name}` follows [semantic versioning][05]. 138 | 139 | ## License 📝 140 | 141 | The project is licensed under the terms of {license}. 142 | 143 | ## Contribution 🤝 144 | 145 | We welcome all people who want to contribute. Please see the 146 | [contributing instructions][03] for more information. 147 | 148 | Contributions in any form (issues, pull requests, etc.) to this project 149 | must adhere to the [Rust's Code of Conduct][10]. 150 | 151 | Unless you explicitly state otherwise, any contribution intentionally 152 | submitted for inclusion in the work by you, as defined in the 153 | Apache-2.0 license, shall be dual licensed as above, without any 154 | additional terms or conditions. 155 | 156 | ## Acknowledgements 💙 157 | 158 | A big thank you to all the awesome contributors of [{name}][04] for their 159 | help and support. 160 | 161 | A special thank you goes to the [Rust Reddit][11] community for 162 | providing a lot of useful suggestions on how to improve this project. 163 | 164 | [00]: {website} "Website of {name}" 165 | [01]: https://opensource.org/license/apache-2-0/ "Apache License, Version 2.0" 166 | [02]: {repository}/{name}/issues "Issues page of {name}" 167 | [03]: {repository}/{name}/blob/main/CONTRIBUTING.md "Contributing guidelines" 168 | [04]: {repository}/{name}/graphs/contributors "Contributors of {name}" 169 | [05]: http://semver.org/ "Semantic Versioning" 170 | [06]: https://crates.io/crates/{name} "Crates.io page of {name}" 171 | [07]: https://docs.rs/{name} "Docs.rs page of {name}" 172 | [08]: https://lib.rs/crates/{name} "Lib.rs page of {name}" 173 | [09]: {repository}/{name}/actions "GitHub Actions page of {name}" 174 | [10]: https://www.rust-lang.org/policies/code-of-conduct "Rust's Code of Conduct" 175 | [11]: https://www.reddit.com/r/rust/ "Rust Reddit community" 176 | [12]: https://www.rust-lang.org/learn/get-started "Rust installation page" 177 | 178 | [crates-badge]: https://img.shields.io/crates/v/{name}.svg?style=for-the-badge 'Crates.io badge' 179 | [divider]: https://kura.pro/common/images/elements/divider.svg "divider" 180 | [docs-badge]: https://img.shields.io/docsrs/{name}.svg?style=for-the-badge 'Docs.rs badge' 181 | [libs-badge]: https://img.shields.io/badge/lib.rs-v{version}-orange.svg?style=for-the-badge 'Lib.rs badge' 182 | [license-badge]: https://img.shields.io/crates/l/{name}.svg?style=for-the-badge 'License badge' 183 | [made-with-rust-badge]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust badge' 184 | -------------------------------------------------------------------------------- /template/TEMPLATE.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | {name}'s logo 10 | 11 | 12 | 13 | # {name} 14 | 15 | {description} 16 | 17 | 18 |
19 | 20 | 21 | [![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] 22 | 23 | • [Website][00] • [Documentation][06] • [Report Bug][02] • [Request Feature][02] • [Contributing Guidelines][03] 24 | 25 | 26 |
27 | 28 | 29 | ![divider][divider] 30 | 31 | ## Overview 📖 32 | 33 | {description} 34 | 35 | ## Features ✨ 36 | 37 | - Feature 1 38 | - Feature 2 39 | - Feature 3 40 | 41 | ## Changelog 📚 42 | 43 | - 44 | 45 | [00]: {website} "Website of {name}" 46 | [01]: https://opensource.org/license/apache-2-0/ "Apache License, Version 2.0" 47 | [02]: {repository}/{name}/issues "Issues page of {name}" 48 | [03]: {repository}/{name}/blob/main/CONTRIBUTING.md "Contributing guidelines of {name}" 49 | [04]: {repository}/{name}/graphs/contributors "Contributors of {name}" 50 | [05]: https://crates.io/crates/{name} "Crates.io page of {name}" 51 | [06]: https://docs.rs/{name} "Docs.rs page of {name}" 52 | [07]: https://lib.rs/crates/{name} "Lib.rs page of {name}" 53 | 54 | [crates-badge]: https://img.shields.io/crates/v/{name}.svg?style=for-the-badge 'Crates.io badge' 55 | [divider]: https://via.placeholder.com/1024x1.png/d8dee4/FFFFFF?text=− "{name}'s divider" 56 | [docs-badge]: https://img.shields.io/docsrs/{name}.svg?style=for-the-badge 'Docs.rs badge' 57 | [libs-badge]: https://img.shields.io/badge/lib.rs-v{version}-orange.svg?style=for-the-badge 'Lib.rs badge' 58 | [license-badge]: https://img.shields.io/crates/l/{name}.svg?style=for-the-badge 'License badge' 59 | [made-with-rust-badge]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust badge' 60 | -------------------------------------------------------------------------------- /template/build.tpl: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // Copyright © 2024 {name}. All rights reserved. 4 | // SPDX-License-Identifier: {license} 5 | 6 | //! This is the main function for the build script. 7 | //! 8 | //! Currently, it only instructs Cargo to re-run this build script if `build.rs` is changed. 9 | fn main() { 10 | // Avoid unnecessary re-building. 11 | println!("cargo:rerun-if-changed=build.rs"); 12 | } 13 | -------------------------------------------------------------------------------- /template/criterion.tpl: -------------------------------------------------------------------------------- 1 | //! # Benchmark: libmake 2 | //! 3 | //! This benchmark tests the performance of the `libmake` crate using the Criterion library. 4 | //! It measures the execution time of the `run` function from the `libmake` crate. 5 | //! 6 | //! ## Purpose 7 | //! 8 | //! The purpose of this benchmark is to assess the execution time of the `run` function 9 | //! from the `{name}` crate under controlled conditions. It helps identify any potential 10 | //! performance bottlenecks and allows for optimization if needed. 11 | //! 12 | //! ## Usage 13 | //! 14 | //! To run this benchmark, ensure that you have the `criterion` and `{name}` crates 15 | //! included as dependencies in your project's `Cargo.toml` file. 16 | //! 17 | //! In your project's code, you can use the `criterion_group` and `criterion_main` macros 18 | //! to define and run benchmarks. In this specific benchmark, the `{name}_benchmark` function 19 | //! is defined to measure the execution time of the `run` function. 20 | //! 21 | //! ```rust 22 | //! extern crate criterion; 23 | //! extern crate {name}; 24 | //! 25 | //! use criterion::{criterion_group, criterion_main, Criterion}; 26 | //! use {name}::run; 27 | //! 28 | //! fn {name}_benchmark(c: &mut Criterion) { 29 | //! c.bench_function("{name}", |b| b.iter(run)); 30 | //! } 31 | //! 32 | //! criterion_group!(benches, {name}_benchmark); 33 | //! criterion_main!(benches); 34 | //! ``` 35 | //! 36 | //! Running this benchmark will provide performance metrics for the `run` function 37 | //! from the `{name}` crate, helping you evaluate and optimize its performance. 38 | 39 | #![allow(missing_docs)] 40 | 41 | use criterion::{criterion_group, criterion_main, Criterion}; 42 | use {name}::run; 43 | 44 | fn {name}_benchmark(c: &mut Criterion) { 45 | c.bench_function("{name}", |b| b.iter(run)); 46 | } 47 | 48 | criterion_group!(benches, {name}_benchmark); 49 | criterion_main!(benches); 50 | -------------------------------------------------------------------------------- /template/deepsource.tpl: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[analyzers]] 4 | name = "rust" 5 | enabled = true 6 | 7 | [analyzers.meta] 8 | msrv = "stable" 9 | -------------------------------------------------------------------------------- /template/deny.tpl: -------------------------------------------------------------------------------- 1 | [licenses] 2 | # The lint level for crates which do not have a detectable license 3 | unlicensed = "deny" 4 | 5 | # List of explicitly allowed licenses 6 | # See https://spdx.org/licenses/ for list of possible licenses 7 | # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. 8 | allow = [ 9 | "Apache-2.0", 10 | "MIT", 11 | "CC0-1.0", 12 | "ISC", 13 | "0BSD", 14 | "BSD-2-Clause", 15 | "BSD-3-Clause", 16 | "Unlicense", 17 | "Unicode-DFS-2016", 18 | ] 19 | 20 | # List of banned licenses 21 | [bans] 22 | multiple-versions = "deny" 23 | 24 | 25 | # The lint level for licenses considered copyleft 26 | copyleft = "deny" 27 | 28 | # Blanket approval or denial for OSI-approved or FSF Free/Libre licenses 29 | # * both - The license will only be approved if it is both OSI-approved *AND* FSF/Free 30 | # * either - The license will be approved if it is either OSI-approved *OR* FSF/Free 31 | # * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF/Free 32 | # * fsf-only - The license will be approved if is FSF/Free *AND NOT* OSI-approved 33 | # * neither - The license will be denied if is FSF/Free *OR* OSI-approved 34 | allow-osi-fsf-free = "either" 35 | 36 | # The confidence threshold for detecting a license from license text. 37 | # The higher the value, the more closely the license text must be to the 38 | # canonical license text of a valid SPDX license file. 39 | # [possible values: any between 0.0 and 1.0]. 40 | confidence-threshold = 0.8 41 | 42 | # The graph highlighting used when creating dotgraphs for crates 43 | # with multiple versions 44 | # * lowest-version - The path to the lowest versioned duplicate is highlighted 45 | # * simplest-path - The path to the version with the fewest edges is highlighted 46 | # * all - Both lowest-version and simplest-path are used 47 | highlight = "all" 48 | 49 | # List of crates that are allowed. Use with care! 50 | allow = [] 51 | 52 | # List of crates to deny 53 | deny = [ 54 | # Each entry the name of a crate and a version range. If version is 55 | # not specified, all versions will be matched. 56 | ] 57 | 58 | # Certain crates/versions that will be skipped when doing duplicate detection. 59 | skip = [] 60 | 61 | # Similarly to `skip` allows you to skip certain crates during duplicate detection, 62 | # unlike skip, it also includes the entire tree of transitive dependencies starting at 63 | # the specified crate, up to a certain depth, which is by default infinite 64 | skip-tree = [] 65 | 66 | 67 | [advisories] 68 | notice = "deny" 69 | unmaintained = "deny" 70 | unsound = "deny" 71 | vulnerability = "deny" -------------------------------------------------------------------------------- /template/example.tpl: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // Copyright © 2024 {name}. All rights reserved. 4 | // SPDX-License-Identifier: "MIT OR Apache-2.0" 5 | 6 | 7 | //! This is an example of how to use the `{name}` crate. 8 | 9 | use {name}::{name}_print; 10 | 11 | fn main() { 12 | {name}_print! { 13 | "Hello, world!" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /template/github/workflows/audit.tpl: -------------------------------------------------------------------------------- 1 | name: 🧪 Audit 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - feat/{name} 8 | pull_request: 9 | branches: 10 | - feat/{name} 11 | release: 12 | types: [created] 13 | 14 | jobs: 15 | dependencies: 16 | name: Audit dependencies 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: hecrj/setup-rust-action@v2 20 | - name: Install cargo-audit 21 | run: cargo install cargo-audit 22 | 23 | - uses: actions/checkout@v4 24 | - name: Resolve dependencies 25 | run: cargo update 26 | 27 | - name: Audit vulnerabilities 28 | run: cargo audit 29 | -------------------------------------------------------------------------------- /template/github/workflows/check.tpl: -------------------------------------------------------------------------------- 1 | name: 🧪 Check 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - feat/{name} 8 | pull_request: 9 | branches: 10 | - feat/{name} 11 | release: 12 | types: [created] 13 | 14 | jobs: 15 | all: 16 | name: Check 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: hecrj/setup-rust-action@v2 20 | with: 21 | components: clippy 22 | - uses: actions/checkout@v4 23 | - name: Check lints 24 | run: cargo check --all-targets --workspace --all-features 25 | -------------------------------------------------------------------------------- /template/github/workflows/coverage.tpl: -------------------------------------------------------------------------------- 1 | name: 📶 Coverage 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | coverage: 14 | name: Code Coverage 15 | runs-on: ubuntu-latest 16 | env: 17 | CARGO_INCREMENTAL: "0" 18 | RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests" 19 | RUSTDOCFLAGS: "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests" 20 | 21 | steps: 22 | # Checkout the repository 23 | - name: Checkout repository 24 | uses: actions/checkout@v4 25 | 26 | # Setup Rust nightly 27 | - name: Install Rust 28 | uses: actions-rs/toolchain@v1 29 | id: toolchain 30 | with: 31 | toolchain: nightly 32 | override: true 33 | 34 | # Configure cache for Cargo 35 | - name: Cache Cargo registry, index 36 | uses: actions/cache@v4 37 | id: cache-cargo 38 | with: 39 | path: | 40 | ~/.cargo/registry 41 | ~/.cargo/bin 42 | ~/.cargo/git 43 | key: linux-${{ steps.toolchain.outputs.rustc_hash }}-rust-cov-${{ hashFiles('**/Cargo.lock') }} 44 | 45 | # Run tests with all features 46 | - name: Test (cargo test) 47 | uses: actions-rs/cargo@v1 48 | with: 49 | command: test 50 | args: "--workspace" 51 | 52 | # Install grcov 53 | - uses: actions-rs/grcov@v0.1 54 | id: coverage 55 | 56 | # Upload to Codecov.io 57 | - name: Upload to Codecov.io 58 | uses: codecov/codecov-action@v4 59 | with: 60 | token: ${{ secrets.CODECOV_TOKEN }} 61 | file: ${{ steps.coverage.outputs.report }} 62 | -------------------------------------------------------------------------------- /template/github/workflows/document.tpl: -------------------------------------------------------------------------------- 1 | name: 🧪 Document 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | release: 11 | types: [created] 12 | 13 | jobs: 14 | all: 15 | name: Document 16 | if: github.ref == 'refs/heads/main' && github.event_name == 'push' 17 | runs-on: ubuntu-latest 18 | concurrency: 19 | group: ${{ github.workflow }}-${{ github.ref }} 20 | steps: 21 | - uses: hecrj/setup-rust-action@v2 22 | with: 23 | rust-version: nightly 24 | 25 | - uses: actions/checkout@v4 26 | 27 | - name: Update libssl 28 | run: | 29 | sudo apt-get update 30 | sudo apt-get install -y libssl1.1 31 | 32 | - name: Generate documentation for all features and publish it 33 | run: | 34 | RUSTDOCFLAGS="--cfg docsrs" \ 35 | cargo doc --no-deps --all-features --workspace 36 | # Write index.html with redirect 37 | echo '' > ./target/doc/index.html 38 | 39 | - name: Deploy 40 | uses: actions/upload-artifact@v4 41 | with: 42 | name: documentation 43 | path: target/doc 44 | if-no-files-found: error 45 | retention-days: 1 46 | 47 | - name: Write CNAME file 48 | run: echo '{name}.github.io' > ./target/doc/CNAME 49 | 50 | - name: Deploy to GitHub Pages 51 | uses: peaceiris/actions-gh-pages@v4 52 | with: 53 | cname: true 54 | commit_message: Deploy documentation at ${{ github.sha }} 55 | github_token: ${{ secrets.GITHUB_TOKEN }} 56 | publish_branch: gh-pages 57 | publish_dir: ./target/doc 58 | user_email: actions@users.noreply.github.com 59 | user_name: github-actions 60 | -------------------------------------------------------------------------------- /template/github/workflows/lint.tpl: -------------------------------------------------------------------------------- 1 | name: 🧪 Lint 2 | 3 | on: 4 | push: 5 | branches: 6 | - feat/{name} 7 | pull_request: 8 | branches: 9 | - feat/{name} 10 | release: 11 | types: [created] 12 | 13 | jobs: 14 | all: 15 | name: Lint 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: hecrj/setup-rust-action@v2 19 | with: 20 | components: clippy 21 | - uses: actions/checkout@v4 22 | - name: Check lints 23 | run: cargo clippy --workspace --all-features --all-targets --no-deps -- -D warnings 24 | -------------------------------------------------------------------------------- /template/github/workflows/test.tpl: -------------------------------------------------------------------------------- 1 | name: 🧪 Test 2 | 3 | on: [pull_request, push] 4 | jobs: 5 | test-lib: 6 | name: Test library 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | os: [ubuntu-latest] 11 | toolchain: [stable, nightly] 12 | continue-on-error: true 13 | 14 | steps: 15 | # Checkout the repository 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | 19 | # Setup Rust 20 | - name: Setup Rust 21 | run: | 22 | rustup toolchain add ${{ matrix.toolchain }} --component llvm-tools-preview 23 | rustup override set ${{ matrix.toolchain }} 24 | 25 | # Configure cache 26 | - name: Configure cache 27 | uses: actions/cache@v4 28 | with: 29 | path: | 30 | ~/.cargo/bin/ 31 | ~/.cargo/registry/index/ 32 | ~/.cargo/registry/cache/ 33 | ~/.cargo/git/db/ 34 | target/ 35 | key: test-${{ runner.os }}-cargo-${{ matrix.toolchain }}-${{ hashFiles('**/Cargo.lock') }} 36 | 37 | # Run tests with all features 38 | - name: Run tests with all features 39 | id: run-tests-all-features 40 | run: cargo test --verbose --workspace --all-features 41 | -------------------------------------------------------------------------------- /template/gitignore.tpl: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.profraw 3 | /.vscode/ 4 | /output/ 5 | /public/ 6 | /target/ 7 | build 8 | Icon? 9 | src/.DS_Store 10 | tarpaulin-report.html -------------------------------------------------------------------------------- /template/lib.tpl: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // Copyright © 2024 {name}. All rights reserved. 4 | // SPDX-License-Identifier: {license} 5 | //! 6 | //! # `{name}` 🦀 7 | //! 8 | //! [![{name}](https://via.placeholder.com/1500x500.png/000000/FFFFFF?text={name})]({website} "{name} - {description}") 9 | //! 10 | //! {description} 11 | //! 12 | //! [![Crates.io](https://img.shields.io/crates/v/{name}.svg?style=for-the-badge&color=success&labelColor=27A006)](https://crates.io/crates/{name} "Crates.io") 13 | //! [![Lib.rs](https://img.shields.io/badge/lib.rs-v{version}-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://lib.rs/crates/{name} "Lib.rs") 14 | //! [![License](https://img.shields.io/crates/l/{name}.svg?style=for-the-badge&color=007EC6&labelColor=03589B)]({license} "{license}") 15 | //! [![Rust](https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust)](https://www.rust-lang.org "Rust") 16 | //! 17 | //! ## Overview 18 | //! 19 | //! {description} 20 | //! 21 | //! ## Features 22 | //! 23 | //! - ... 24 | //! - ... 25 | //! - ... 26 | //! 27 | //! ## Usage 28 | //! 29 | //! Add the following to your `Cargo.toml` file: 30 | //! 31 | //! ```toml 32 | //! [dependencies] 33 | //! {name} = {version} 34 | //! serde = { version = "1.0.197", features = ["derive"] } 35 | //! serde_json = "1.0.115" 36 | //! ``` 37 | //! 38 | //! ## Examples 39 | //! 40 | //! Check out the examples folder for helpful snippets of code that 41 | //! demonstrate how to use the `{name}` library. You can also check out 42 | //! the [documentation](https://docs.rs/{name}) for more information on 43 | //! how to use the library. 44 | //! 45 | //! ```rust 46 | //! use {name}::{name}; 47 | //! 48 | //! ``` 49 | //! 50 | //! ## License 51 | //! 52 | //! The project is licensed under the terms of the {license} license. 53 | //! 54 | #![doc( 55 | html_favicon_url = "", 56 | html_logo_url = "", 57 | html_root_url = "https://docs.rs/{name}" 58 | )] 59 | #![crate_name = "{name}"] 60 | #![crate_type = "lib"] 61 | 62 | /// The `macros` module contains functions for generating macros. 63 | pub mod macros; 64 | 65 | use serde::{Deserialize, Serialize}; 66 | use std::error::Error; 67 | 68 | #[non_exhaustive] 69 | #[derive( 70 | Clone, 71 | Debug, 72 | Deserialize, 73 | Eq, 74 | Hash, 75 | Ord, 76 | PartialEq, 77 | PartialOrd, 78 | Serialize, 79 | )] 80 | 81 | #[allow(non_camel_case_types)] 82 | /// `{name}` is a data structure that ... 83 | pub struct {name} { 84 | // Add any data fields needed here 85 | } 86 | 87 | /// This is the main entry point for the `{name}` library. 88 | pub fn run() -> Result<(), Box> { 89 | // Add your code here 90 | let name = "{name}"; 91 | println!("Hello, {}!", { name }.to_uppercase()); 92 | Ok(()) 93 | } 94 | 95 | 96 | impl {name} { 97 | /// Creates a new instance of `{name}` 98 | pub fn new() -> Self { 99 | Self { 100 | // Initialize any data fields here 101 | } 102 | } 103 | } 104 | 105 | impl Default for {name} { 106 | /// Creates a new instance of `{name}` with default values 107 | fn default() -> Self { 108 | Self::new() 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /template/macros.tpl: -------------------------------------------------------------------------------- 1 | //! # Macros for the `{name}` crate. 2 | //! 3 | //! This crate provides the following macros: 4 | //! 5 | //! - `{name}`: The main macro for the `{name}` crate. 6 | //! - `{name}_print`: Prints the arguments to the console. 7 | //! - `{name}_vec`: Creates a new vector of the given elements. 8 | //! - `{name}_map`: Creates a new map of the given key-value pairs. 9 | //! - `{name}_assert`: Checks if the given expression is true. 10 | //! - `{name}_min`: Returns the minimum of the given values. 11 | //! - `{name}_max`: Returns the maximum of the given values. 12 | //! - `{name}_split`: Splits a string into a vector of words. 13 | //! - `{name}_join`: Joins a vector of strings into a single string. 14 | //! - `{name}_print_vec`: Prints a vector of elements to the console. 15 | //! 16 | 17 | /// This macro takes any number of arguments and parses them into a 18 | /// Rust value. 19 | #[macro_export] 20 | macro_rules! {name} { 21 | ($($tt:tt)*) => { 22 | // Parse the arguments into a Rust value. 23 | $crate::parse!($($tt)*) 24 | }; 25 | } 26 | 27 | /// This macro prints the arguments to the console. 28 | #[macro_export] 29 | macro_rules! {name}_print { 30 | ($($arg:tt)*) => { 31 | println!("{}", format_args!("{}", $($arg)*)); 32 | }; 33 | } 34 | 35 | /// This macro creates a new vector of the given elements. 36 | #[macro_export] 37 | macro_rules! {name}_vec { 38 | ($($elem:expr),*) => {{ 39 | let mut v = Vec::new(); 40 | $(v.push($elem);)* 41 | v 42 | }}; 43 | } 44 | 45 | /// This macro creates a new map of the given key-value pairs. 46 | #[macro_export] 47 | macro_rules! {name}_map { 48 | ($($key:expr => $value:expr),*) => {{ 49 | use std::collections::HashMap; 50 | let mut m = HashMap::new(); 51 | $(m.insert($key, $value);)* 52 | m 53 | }}; 54 | } 55 | 56 | /// This macro checks if the given expression is true. 57 | #[macro_export] 58 | macro_rules! {name}_assert { 59 | ($($arg:tt)*) => { 60 | if !$($arg)* { 61 | panic!("Assertion failed!"); 62 | } 63 | }; 64 | } 65 | 66 | /// This macro returns the minimum of the given values. 67 | #[macro_export] 68 | macro_rules! {name}_min { 69 | ($($x:expr),*) => {{ 70 | let mut min = $($x)*; 71 | $(if min > $x { min = $x; })* 72 | min 73 | }}; 74 | } 75 | 76 | /// This macro returns the maximum of the given values. 77 | #[macro_export] 78 | macro_rules! {name}_max { 79 | ($($x:expr),*) => {{ 80 | let mut max = $($x)*; 81 | $(if max < $x { max = $x; })* 82 | max 83 | }}; 84 | } 85 | 86 | /// This macro takes a string and splits it into a vector of words. 87 | #[macro_export] 88 | macro_rules! {name}_split { 89 | ($s:expr) => {{ 90 | let mut v = Vec::new(); 91 | for w in $s.split_whitespace() { 92 | v.push(w.to_string()); 93 | } 94 | v 95 | }}; 96 | } 97 | 98 | /// This macro takes a vector of strings and joins them together into a 99 | /// single string. 100 | #[macro_export] 101 | macro_rules! {name}_join { 102 | ($($s:expr),*) => {{ 103 | let mut s = String::new(); 104 | $( 105 | s += &$s; 106 | )* 107 | s 108 | }}; 109 | } 110 | 111 | /// This macro takes a vector of elements and prints them to the 112 | /// console. 113 | #[macro_export] 114 | macro_rules! {name}_print_vec { 115 | ($($v:expr),*) => {{ 116 | for v in $($v),* { 117 | println!("{}", v); 118 | } 119 | }}; 120 | } 121 | -------------------------------------------------------------------------------- /template/main.tpl: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // Copyright © 2024 {name}. All rights reserved. 4 | // SPDX-License-Identifier: {license} 5 | 6 | //! This crate contains the main entry point for the `{name}` application. 7 | 8 | /// This is the main entry point for the `{name}` application. 9 | fn main() { 10 | // Call the `run()` function from the `{name}` module. 11 | if let Err(err) = {name}::run() { 12 | eprintln!("Error running {name}: {}", err); 13 | std::process::exit(1); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /template/rustfmt.tpl: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright © 2023 {name}. All rights reserved. 2 | # SPDX-License-Identifier: {license} 3 | 4 | # See https://github.com/rust-lang/rustfmt/blob/master/Configurations.md 5 | # for more configuration options 6 | 7 | comment_width = 72 # Maximum line width for comments 8 | doc_comment_code_block_width = 72 # Maximum line width for code blocks in doc comments 9 | edition = "2021" # Use a single edition only (Edition 2018 or Edition 2021) 10 | empty_item_single_line = true # Put empty items on a single line 11 | force_explicit_abi = true # Force explicit abi 12 | format_code_in_doc_comments = true # Format code snippets in doc comments 13 | format_macro_bodies = true # Format macro bodies 14 | format_macro_matchers = true # Format macro matchers 15 | group_imports = "StdExternalCrate" # Group imports by crate 16 | hard_tabs = false # Use spaces instead of tabs 17 | imports_granularity = "Module" # Group imports by module 18 | imports_layout = "HorizontalVertical" # Layout imports horizontally and vertically 19 | max_width = 72 # Maximum line width 20 | merge_derives = true # Merge derives 21 | newline_style = "Unix" # Prevent carriage returns from being added to the end of lines 22 | normalize_comments = true # Normalize comments 23 | normalize_doc_attributes = true # Normalize doc attributes 24 | overflow_delimited_expr = true # Allow overflowing delimited expressions 25 | remove_nested_parens = true # Remove nested parens 26 | reorder_imports = true # Reorder imports 27 | reorder_modules = true # Reorder modules 28 | tab_spaces = 4 # Use 4 spaces for indentation 29 | use_field_init_shorthand = true # Use field initialization shorthand when possible 30 | use_small_heuristics = "Max" # Use max heuristics 31 | use_try_shorthand = true # Use try shorthand when possible 32 | wrap_comments = true # Wrap comments when line width exceeds max max_width -------------------------------------------------------------------------------- /template/test.tpl: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | 4 | use {name}::{name}; 5 | 6 | #[test] 7 | fn test_{name}() { 8 | let {name} = {name}::new(); 9 | assert_eq!({name}, {name}::default()); 10 | } 11 | } -------------------------------------------------------------------------------- /template/test_test.tpl: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | 4 | use {name}::{name}; 5 | 6 | #[test] 7 | fn test_{name}() { 8 | let {name} = {name}::new(); 9 | assert_eq!({name}, {name}::default()); 10 | } 11 | } -------------------------------------------------------------------------------- /tests/data/mylibrary.csv: -------------------------------------------------------------------------------- 1 | author,build,categories,description,documentation,edition,email,homepage,keywords,license,name,output,readme,repository,rustversion,version,website 2 | 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.60,0.2.6,https://test.com 3 | -------------------------------------------------------------------------------- /tests/data/mylibrary.ini: -------------------------------------------------------------------------------- 1 | author = "Me" 2 | build = "build.rs" 3 | categories = ["category 1","category 2","category 3"] 4 | description = "A library for doing things" 5 | documentation = "https://lib.rs/crates/my_library" 6 | edition = "2021" 7 | email = "test@test.com" 8 | homepage = "https://test.com" 9 | keywords = ['keyword 1','keyword 2','keyword 3'] 10 | license = "MIT OR Apache-2.0" 11 | name = "my_library" 12 | output = "my_library" 13 | readme = "README.md" 14 | repository = "https://github.com/test/test" 15 | rustversion = "1.60" 16 | version = "0.2.6" 17 | website = "https://test.com" 18 | -------------------------------------------------------------------------------- /tests/data/mylibrary.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Me", 3 | "build": "build.rs", 4 | "categories": "['category 1','category 2']", 5 | "description": "A library for doing things", 6 | "documentation": "https://lib.rs/crates/my_library", 7 | "edition": "2021", 8 | "email": "test@test.com", 9 | "homepage": "https://test.com", 10 | "keywords": "['keyword1', 'keyword2']", 11 | "license": "MIT OR Apache-2.0", 12 | "name": "my_library", 13 | "output": "my_library", 14 | "readme": "README.md", 15 | "repository": "https://github.com/test/test", 16 | "rustversion": "1.60", 17 | "version": "0.2.6", 18 | "website": "https://test.com" 19 | } 20 | -------------------------------------------------------------------------------- /tests/data/mylibrary.toml: -------------------------------------------------------------------------------- 1 | author = "Me" 2 | build = "build.rs" 3 | categories = "'category 1','category 2','category 3'" 4 | description = "A library for doing things" 5 | documentation = "https://lib.rs/crates/my_library" 6 | edition = "2021" 7 | email = "test@test.com" 8 | homepage = "https://test.com" 9 | keywords = "'keyword 1','keyword 2','keyword 3'" 10 | license = "MIT OR Apache-2.0" 11 | name = "my_library" 12 | output = "my_library" 13 | readme = "README.md" 14 | repository = "https://github.com/test/test" 15 | rustversion = "1.60" 16 | version = "0.2.6" 17 | website = "https://test.com" 18 | -------------------------------------------------------------------------------- /tests/data/mylibrary.yaml: -------------------------------------------------------------------------------- 1 | author: Me 2 | build: build.rs 3 | categories: "'category 1','category 2','category 3'" 4 | description: A library for doing things 5 | documentation: https://lib.rs/crates/my_library 6 | edition: '2021' 7 | email: test@test.com 8 | homepage: https://test.com 9 | keywords: "'keyword 1','keyword 2','keyword 3'" 10 | license: 'MIT OR Apache-2.0' 11 | name: my_library 12 | output: my_library 13 | readme: README.md 14 | repository: https://github.com/test/test 15 | rustversion: '1.60' 16 | version: '0.2.6' 17 | website: https://test.com 18 | -------------------------------------------------------------------------------- /tests/generators/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright notice and licensing information. 2 | // These lines indicate the copyright of the software and its licensing terms. 3 | // SPDX-License-Identifier: Apache-2.0 OR MIT indicates dual licensing under Apache 2.0 or MIT licenses. 4 | // Copyright © 2023-2024 LibMake. All rights reserved. 5 | 6 | /// The `test_ascii` module contains functionality for generating ASCII art from 7 | /// text using the FIGlet library. 8 | pub mod test_ascii; 9 | 10 | /// The `test_args` module contains functionality for parsing command-line arguments. 11 | pub mod test_args; 12 | 13 | /// The `test_csv` module contains functionality for parsing CSV files. 14 | pub mod test_csv; 15 | 16 | /// The `test_ini` module contains functionality for parsing INI files. 17 | pub mod test_ini; 18 | 19 | /// The `test_json` module contains functionality for parsing JSON files. 20 | pub mod test_json; 21 | 22 | /// The `test_toml` module contains functionality for parsing TOML files. 23 | pub mod test_toml; 24 | 25 | /// The `test_yaml` module contains functionality for parsing YAML files. 26 | pub mod test_yaml; 27 | -------------------------------------------------------------------------------- /tests/generators/test_ascii.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use libmake::{ 4 | generators::ascii::{generate_ascii_art, load_standard_font}, 5 | macro_ascii, 6 | models::error_ascii_art::AsciiArtError, 7 | }; 8 | 9 | #[test] 10 | fn test_generate_ascii_art_success() { 11 | let text = "Hello, world!"; 12 | let result = generate_ascii_art(text); 13 | assert!(result.is_ok()); 14 | let ascii_art = result.unwrap(); 15 | assert!(!ascii_art.is_empty()); 16 | } 17 | 18 | #[test] 19 | fn test_generate_ascii_art_empty_text() { 20 | let text = ""; 21 | let result = generate_ascii_art(text); 22 | assert!(result.is_err()); 23 | assert!(matches!( 24 | result.unwrap_err(), 25 | AsciiArtError::ConversionError 26 | )); 27 | } 28 | 29 | #[test] 30 | fn test_load_standard_font_success() { 31 | let result = load_standard_font(); 32 | assert!(result.is_ok()); 33 | } 34 | 35 | #[test] 36 | fn test_generate_ascii_art_conversion_error() { 37 | let text = "\u{1F600}"; // Emoji character 38 | let result = generate_ascii_art(text); 39 | assert!(result.is_err()); 40 | assert!(matches!( 41 | result.unwrap_err(), 42 | AsciiArtError::ConversionError 43 | )); 44 | } 45 | 46 | #[test] 47 | fn test_generate_ascii_art_multiple_lines() { 48 | let text = "Hello,\nworld!"; 49 | let result = generate_ascii_art(text); 50 | assert!(result.is_ok()); 51 | let ascii_art = result.unwrap(); 52 | assert!(ascii_art.contains('\n')); 53 | } 54 | 55 | #[test] 56 | fn test_generate_ascii_art_special_characters() { 57 | let text = "!@#$%^&*()_+"; 58 | let result = generate_ascii_art(text); 59 | assert!(result.is_ok()); 60 | let ascii_art = result.unwrap(); 61 | assert!(!ascii_art.is_empty()); 62 | } 63 | 64 | #[test] 65 | fn test_macro_ascii_success() { 66 | let ascii_art = macro_ascii!("Hello, world!"); 67 | assert!(!ascii_art.is_empty()); 68 | } 69 | 70 | #[test] 71 | #[should_panic( 72 | expected = "Failed to generate ASCII art: Failed to convert text to ASCII art" 73 | )] 74 | fn test_macro_ascii_empty_text() { 75 | let _ = macro_ascii!(""); 76 | } 77 | 78 | #[test] 79 | #[should_panic( 80 | expected = "Failed to generate ASCII art: Failed to convert text to ASCII art" 81 | )] 82 | fn test_macro_ascii_conversion_error() { 83 | let _ = macro_ascii!("\u{1F600}"); // Emoji character 84 | } 85 | 86 | #[test] 87 | fn test_macro_ascii_multiple_lines() { 88 | let ascii_art = macro_ascii!("Hello,\nworld!"); 89 | assert!(ascii_art.contains('\n')); 90 | } 91 | 92 | #[test] 93 | fn test_macro_ascii_special_characters() { 94 | let ascii_art = macro_ascii!("!@#$%^&*()_+"); 95 | assert!(!ascii_art.is_empty()); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /tests/generators/test_csv.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use libmake::generators::csv::generate_from_csv; 4 | use std::fs::File; 5 | use std::io::Write; 6 | 7 | #[test] 8 | fn test_generate_from_csv_valid() { 9 | // Create a temporary CSV file 10 | let csv_content = "\ 11 | author,build,categories,description,documentation,edition,email,homepage,keywords,license,name,output,readme,repository,rustversion,version,website\n\ 12 | John Doe,cargo build,web,Sample project,,2021,john@example.com,https://example.com,example,Rust-1.0,SampleProject,/tmp/output,README.md,https://github.com/example,1.51.0,0.1.0,https://example.com\n"; 13 | 14 | let path = "/tmp/test_valid.csv"; 15 | let mut file = File::create(path).unwrap(); 16 | file.write_all(csv_content.as_bytes()).unwrap(); 17 | 18 | // Call the function and check for success 19 | let result = generate_from_csv(path); 20 | assert!(result.is_ok()); 21 | 22 | // Clean up 23 | std::fs::remove_file(path).unwrap(); 24 | } 25 | 26 | #[test] 27 | fn test_generate_from_csv_invalid_path() { 28 | let result = generate_from_csv("/invalid/path/to/csv"); 29 | assert!(result.is_err()); 30 | } 31 | 32 | #[test] 33 | fn test_generate_from_csv_malformed_csv() { 34 | // Create a temporary malformed CSV file 35 | let csv_content = "author,build,categories,description,documentation,edition,email,homepage,keywords,license,name,output,readme,repository,rustversion,version,website\n\ 36 | John Doe,cargo build,web,Sample project,,2021,john@example.com,https://example.com,example,Rust-1.0,SampleProject,/tmp/output,README.md,https://github.com/example,1.51.0,0.1.0"; 37 | 38 | let path = "/tmp/test_malformed.csv"; 39 | let mut file = File::create(path).unwrap(); 40 | file.write_all(csv_content.as_bytes()).unwrap(); 41 | 42 | // Call the function and check for error 43 | let result = generate_from_csv(path); 44 | assert!(result.is_err()); 45 | 46 | // Clean up 47 | std::fs::remove_file(path).unwrap(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests/generators/test_ini.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use libmake::generators::ini::generate_from_ini; 4 | use std::fs::File; 5 | use std::io::Write; 6 | use tempfile::tempdir; 7 | 8 | #[test] 9 | fn test_generate_from_ini_valid_ini() { 10 | let file_path = "./tests/data/mylibrary.ini"; 11 | generate_from_ini(file_path).unwrap(); 12 | assert_eq!(true, true); 13 | } 14 | 15 | #[test] 16 | fn test_generate_from_ini_file_not_found() { 17 | let result = generate_from_ini("non_existent_file.ini"); 18 | assert!(result.is_err()); 19 | } 20 | 21 | #[test] 22 | fn test_generate_from_ini_cannot_read() { 23 | let dir = tempdir().unwrap(); 24 | let file_path = dir.path().join("test.ini"); 25 | 26 | // Create a directory with the same name to cause a read error 27 | std::fs::create_dir(&file_path).unwrap(); 28 | 29 | let result = generate_from_ini(file_path.to_str().unwrap()); 30 | assert!(result.is_err()); 31 | } 32 | 33 | #[test] 34 | fn test_generate_from_ini_invalid_utf8() { 35 | let dir = tempdir().unwrap(); 36 | let file_path = dir.path().join("test.ini"); 37 | 38 | // Write invalid UTF-8 data to the file 39 | let mut file = File::create(&file_path).unwrap(); 40 | file.write_all(&[0x80, 0x81, 0x82]).unwrap(); 41 | 42 | let result = generate_from_ini(file_path.to_str().unwrap()); 43 | assert!(result.is_err()); 44 | } 45 | 46 | #[test] 47 | fn test_generate_from_ini_parse_error() { 48 | let dir = tempdir().unwrap(); 49 | let file_path = dir.path().join("test.ini"); 50 | 51 | let invalid_ini_data = r#" 52 | [invalid_section] 53 | invalid_field = "invalid_value" 54 | "#; 55 | 56 | let mut file = File::create(&file_path).unwrap(); 57 | file.write_all(invalid_ini_data.as_bytes()).unwrap(); 58 | 59 | let result = generate_from_ini(file_path.to_str().unwrap()); 60 | assert!(result.is_err()); 61 | } 62 | 63 | #[test] 64 | fn test_generate_from_ini_generate_files_error() { 65 | // This test assumes that macro_generate_files! returns an error for certain parameters. 66 | // Adjust the test if necessary based on the actual implementation of the macro. 67 | let dir = tempdir().unwrap(); 68 | let file_path = dir.path().join("test.ini"); 69 | 70 | let ini_data = r#" 71 | [project] 72 | output = "test_output_dir" 73 | "#; 74 | 75 | let mut file = File::create(&file_path).unwrap(); 76 | file.write_all(ini_data.as_bytes()).unwrap(); 77 | 78 | // Mocking or adjusting the macro_generate_files! to return an error would be necessary. 79 | // This part of the test may require more advanced setup depending on the macro implementation. 80 | 81 | let result = generate_from_ini(file_path.to_str().unwrap()); 82 | assert!(result.is_err()); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /tests/generators/test_json.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use libmake::generators::json::generate_from_json; 4 | use std::fs::File; 5 | use std::io::Write; 6 | use tempfile::tempdir; 7 | 8 | #[test] 9 | fn test_generate_from_json_success() { 10 | let file_path = "./tests/data/mylibrary.json"; 11 | generate_from_json(file_path).unwrap(); 12 | assert_eq!(true, true); 13 | } 14 | 15 | #[test] 16 | fn test_generate_from_json_file_not_found() { 17 | let result = generate_from_json("non_existent_file.json"); 18 | assert!(result.is_err()); 19 | } 20 | 21 | #[test] 22 | fn test_generate_from_json_cannot_read() { 23 | let dir = tempdir().unwrap(); 24 | let file_path = dir.path().join("test.json"); 25 | 26 | // Create a directory with the same name to cause a read error 27 | std::fs::create_dir(&file_path).unwrap(); 28 | 29 | let result = generate_from_json(file_path.to_str().unwrap()); 30 | assert!(result.is_err()); 31 | } 32 | 33 | #[test] 34 | fn test_generate_from_json_invalid_utf8() { 35 | let dir = tempdir().unwrap(); 36 | let file_path = dir.path().join("test.json"); 37 | 38 | // Write invalid UTF-8 data to the file 39 | let mut file = File::create(&file_path).unwrap(); 40 | file.write_all(&[0x80, 0x81, 0x82]).unwrap(); 41 | 42 | let result = generate_from_json(file_path.to_str().unwrap()); 43 | assert!(result.is_err()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/generators/test_toml.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use libmake::generators::toml::generate_from_toml; 4 | use std::fs::File; 5 | use std::io::Write; 6 | use tempfile::tempdir; 7 | 8 | #[test] 9 | fn test_generate_from_toml_success() { 10 | let file_path = "./tests/data/mylibrary.toml"; 11 | generate_from_toml(file_path).unwrap(); 12 | assert_eq!(true, true); 13 | } 14 | 15 | #[test] 16 | fn test_generate_from_toml_file_not_found() { 17 | let result = generate_from_toml("non_existent_file.toml"); 18 | assert!(result.is_err()); 19 | } 20 | 21 | #[test] 22 | fn test_generate_from_toml_cannot_read() { 23 | let dir = tempdir().unwrap(); 24 | let file_path = dir.path().join("test.toml"); 25 | 26 | // Create a directory with the same name to cause a read error 27 | std::fs::create_dir(&file_path).unwrap(); 28 | 29 | let result = generate_from_toml(file_path.to_str().unwrap()); 30 | assert!(result.is_err()); 31 | } 32 | 33 | #[test] 34 | fn test_generate_from_toml_invalid_utf8() { 35 | let dir = tempdir().unwrap(); 36 | let file_path = dir.path().join("test.toml"); 37 | 38 | // Write invalid UTF-8 data to the file 39 | let mut file = File::create(&file_path).unwrap(); 40 | file.write_all(&[0x80, 0x81, 0x82]).unwrap(); 41 | 42 | let result = generate_from_toml(file_path.to_str().unwrap()); 43 | assert!(result.is_err()); 44 | } 45 | 46 | #[test] 47 | fn test_generate_from_toml_deserialize_error() { 48 | let dir = tempdir().unwrap(); 49 | let file_path = dir.path().join("test.toml"); 50 | 51 | let invalid_toml_data = r#" 52 | invalid_field = "invalid_value" 53 | "#; 54 | 55 | let mut file = File::create(&file_path).unwrap(); 56 | file.write_all(invalid_toml_data.as_bytes()).unwrap(); 57 | 58 | let result = generate_from_toml(file_path.to_str().unwrap()); 59 | assert!(result.is_err()); 60 | } 61 | 62 | #[test] 63 | fn test_generate_from_toml_generate_files_error() { 64 | // This test assumes that macro_generate_files! returns an error for certain parameters. 65 | // Adjust the test if necessary based on the actual implementation of the macro. 66 | let dir = tempdir().unwrap(); 67 | let file_path = dir.path().join("test.toml"); 68 | 69 | let toml_data = r#" 70 | output = "test_output_dir" 71 | "#; 72 | 73 | let mut file = File::create(&file_path).unwrap(); 74 | file.write_all(toml_data.as_bytes()).unwrap(); 75 | 76 | // Mocking or adjusting the macro_generate_files! to return an error would be necessary. 77 | // This part of the test may require more advanced setup depending on the macro implementation. 78 | 79 | let result = generate_from_toml(file_path.to_str().unwrap()); 80 | assert!(result.is_err()); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /tests/generators/test_yaml.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use libmake::generators::yaml::generate_from_yaml; 4 | use std::io::Write; 5 | use std::fs::File; 6 | use tempfile::tempdir; 7 | 8 | #[test] 9 | fn test_generate_from_yaml_success() { 10 | let file_path = "./tests/data/mylibrary.yaml"; 11 | generate_from_yaml(file_path).unwrap(); 12 | assert_eq!(true, true); 13 | } 14 | 15 | #[test] 16 | fn test_generate_from_yaml_file_not_found() { 17 | let result = generate_from_yaml("non_existent_file.yaml"); 18 | assert!(result.is_err()); 19 | } 20 | 21 | #[test] 22 | fn test_generate_from_yaml_cannot_read() { 23 | let dir = tempdir().unwrap(); 24 | let file_path = dir.path().join("test.yaml"); 25 | 26 | // Create a directory with the same name to cause a read error 27 | std::fs::create_dir(&file_path).unwrap(); 28 | 29 | let result = generate_from_yaml(file_path.to_str().unwrap()); 30 | assert!(result.is_err()); 31 | } 32 | 33 | #[test] 34 | fn test_generate_from_yaml_invalid_utf8() { 35 | let dir = tempdir().unwrap(); 36 | let file_path = dir.path().join("test.yaml"); 37 | 38 | // Write invalid UTF-8 data to the file 39 | let mut file = File::create(&file_path).unwrap(); 40 | file.write_all(&[0x80, 0x81, 0x82]).unwrap(); 41 | 42 | let result = generate_from_yaml(file_path.to_str().unwrap()); 43 | assert!(result.is_err()); 44 | } 45 | 46 | #[test] 47 | fn test_generate_from_yaml_deserialize_error() { 48 | let dir = tempdir().unwrap(); 49 | let file_path = dir.path().join("test.yaml"); 50 | 51 | let invalid_yaml_data = r#" 52 | invalid_field: invalid_value 53 | "#; 54 | 55 | let mut file = File::create(&file_path).unwrap(); 56 | file.write_all(invalid_yaml_data.as_bytes()).unwrap(); 57 | 58 | let result = generate_from_yaml(file_path.to_str().unwrap()); 59 | assert!(result.is_err()); 60 | } 61 | 62 | #[test] 63 | fn test_generate_from_yaml_generate_files_error() { 64 | // This test assumes that macro_generate_files! returns an error for certain parameters. 65 | // Adjust the test if necessary based on the actual implementation of the macro. 66 | let dir = tempdir().unwrap(); 67 | let file_path = dir.path().join("test.yaml"); 68 | 69 | let yaml_data = r#" 70 | output: test_output_dir 71 | "#; 72 | 73 | let mut file = File::create(&file_path).unwrap(); 74 | file.write_all(yaml_data.as_bytes()).unwrap(); 75 | 76 | // Mocking or adjusting the macro_generate_files! to return an error would be necessary. 77 | // This part of the test may require more advanced setup depending on the macro implementation. 78 | 79 | let result = generate_from_yaml(file_path.to_str().unwrap()); 80 | assert!(result.is_err()); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /tests/macros/mod.rs: -------------------------------------------------------------------------------- 1 | /// The `test_ascii_macros` module contains tests for the ascii_macros module. 2 | pub mod test_ascii_macros; 3 | 4 | /// The `test_directory_macros` module contains tests for the directory_macros module. 5 | pub mod test_directory_macros; 6 | 7 | /// The `test_file_macros` module contains tests for the file_macros module. 8 | pub mod test_file_macros; 9 | 10 | /// The `test_generator_macros` module contains tests for the generator_macros module. 11 | pub mod test_generator_macros; 12 | 13 | /// The `test_log_macros` module contains tests for the log_macros module. 14 | pub mod test_log_macros; 15 | 16 | /// The `test_utility_macros` module contains tests for the utility_macros module. 17 | pub mod test_utility_macros; 18 | -------------------------------------------------------------------------------- /tests/macros/test_ascii_macros.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use libmake::macro_ascii; 4 | 5 | #[test] 6 | fn test_macro_ascii_success() { 7 | let art = macro_ascii!("Hi"); 8 | assert_eq!(art, " _ _ _ \n | | | | (_)\n | |_| | | |\n | _ | | |\n |_| |_| |_|\n \n"); 9 | } 10 | 11 | #[test] 12 | #[should_panic( 13 | expected = "Failed to generate ASCII art: Failed to convert text to ASCII art" 14 | )] 15 | fn test_macro_ascii_empty_input() { 16 | let _art = macro_ascii!(""); 17 | } 18 | 19 | #[test] 20 | #[should_panic( 21 | expected = "Failed to generate ASCII art: Failed to convert text to ASCII art" 22 | )] 23 | fn test_macro_ascii_invalid_input() { 24 | let _art = macro_ascii!("🦀"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/macros/test_directory_macros.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use libmake::{ 4 | macro_check_directory, macro_cleanup_directories, 5 | macro_create_directories, 6 | }; 7 | use std::fs; 8 | use std::path::Path; 9 | use tempfile::tempdir; 10 | 11 | #[test] 12 | fn test_macro_check_directory() { 13 | let temp_dir = tempdir().unwrap(); 14 | let path = temp_dir.path().join("logs"); 15 | 16 | // Test creating a new directory 17 | macro_check_directory!(&path, "logs"); 18 | assert!(path.exists() && path.is_dir()); 19 | 20 | // Test directory already exists 21 | macro_check_directory!(&path, "logs"); 22 | assert!(path.exists() && path.is_dir()); 23 | } 24 | 25 | #[test] 26 | fn test_macro_create_directories() { 27 | let temp_dir = tempdir().unwrap(); 28 | let path1 = temp_dir.path().join("logs1"); 29 | let path2 = temp_dir.path().join("logs2"); 30 | 31 | // Test creating multiple directories 32 | macro_create_directories!(&path1, &path2).unwrap(); 33 | assert!(path1.exists() && path1.is_dir()); 34 | assert!(path2.exists() && path2.is_dir()); 35 | } 36 | 37 | #[test] 38 | fn test_macro_cleanup_directories() { 39 | let temp_dir = tempdir().unwrap(); 40 | let path1 = temp_dir.path().join("logs1"); 41 | let path2 = temp_dir.path().join("logs2"); 42 | 43 | // Create directories to clean up 44 | fs::create_dir_all(&path1).unwrap(); 45 | fs::create_dir_all(&path2).unwrap(); 46 | 47 | // Test cleaning up directories 48 | macro_cleanup_directories!(&path1, &path2); 49 | assert!(!path1.exists()); 50 | assert!(!path2.exists()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/macros/test_file_macros.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use libmake::generate_file; 4 | use std::cell::RefCell; 5 | 6 | // Mock generator function 7 | fn mock_generator_success(_: &str) -> Result<(), String> { 8 | Ok(()) 9 | } 10 | 11 | // Mock generator function that returns an error 12 | fn mock_generator_error(_: &str) -> Result<(), String> { 13 | Err("Mock error".to_string()) 14 | } 15 | 16 | thread_local! { 17 | static LAST_ERROR: RefCell> = const { RefCell::new(None) }; 18 | } 19 | 20 | // Mock eprintln! macro to capture the error messages 21 | macro_rules! eprintln { 22 | ($($arg:tt)*) => { 23 | LAST_ERROR.with(|last_error| { 24 | *last_error.borrow_mut() = Some(format!($($arg)*)); 25 | }); 26 | }; 27 | } 28 | 29 | #[test] 30 | fn test_generate_file_success() { 31 | generate_file!( 32 | "test", 33 | "non_empty_value", 34 | mock_generator_success 35 | ); 36 | LAST_ERROR.with(|last_error| { 37 | assert!(last_error.borrow().is_none()); 38 | }); 39 | } 40 | 41 | #[test] 42 | fn test_generate_file_empty_value() { 43 | generate_file!("test", "", mock_generator_success); 44 | LAST_ERROR.with(|last_error| { 45 | assert!(last_error.borrow().is_none()); 46 | }); 47 | } 48 | 49 | #[test] 50 | fn test_generate_file_error() { 51 | generate_file!("test", "non_empty_value", mock_generator_error); 52 | LAST_ERROR.with(|last_error| { 53 | assert_eq!( 54 | *last_error.borrow(), 55 | Some( 56 | "Error generating test file: Mock error" 57 | .to_string() 58 | ) 59 | ); 60 | }); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tests/macros/test_generator_macros.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | 4 | use libmake::models::model_params::FileGenerationParams; 5 | use std::path::Path; 6 | 7 | use libmake::macro_create_directories; 8 | 9 | use libmake::{ 10 | macro_generate_files, macro_generate_from_config, 11 | macro_generate_from_csv, macro_generate_from_json, 12 | macro_generate_from_yaml, 13 | }; 14 | 15 | // Unit test for the `create_directory()` function. 16 | #[test] 17 | fn test_create_directory() { 18 | let result = macro_create_directories!("my_library"); 19 | match result { 20 | Ok(()) => println!("Directory created successfully!"), 21 | Err(err) => println!("Error creating directory: {}", err), 22 | } 23 | } 24 | // Unit test for the `generate_files()` function. 25 | #[test] 26 | #[allow(clippy::redundant_clone)] 27 | fn test_generate_files() -> Result<(), String> { 28 | let mut params = FileGenerationParams::new(); 29 | params.output = Some("my_library".into()); 30 | macro_generate_files!(params.clone())?; 31 | Ok(()) 32 | } 33 | // Unit test for the `generate_from_csv()` function. 34 | #[test] 35 | fn test_generate_from_csv() -> Result<(), String> { 36 | macro_generate_from_csv!("./tests/data/mylibrary.csv")?; 37 | Ok(()) 38 | } 39 | // Unit test for the `generate_from_json()` function. 40 | #[test] 41 | fn test_generate_from_json() -> Result<(), String> { 42 | macro_generate_from_json!("./tests/data/mylibrary.json")?; 43 | Ok(()) 44 | } 45 | // Unit test for the `generate_from_yaml()` function. 46 | #[test] 47 | fn test_generate_from_yaml() -> Result<(), String> { 48 | macro_generate_from_yaml!("./tests/data/mylibrary.yaml")?; 49 | Ok(()) 50 | } 51 | // Unit test for the `generate_from_config()` function. 52 | #[test] 53 | fn test_generate_from_config() -> Result<(), String> { 54 | macro_generate_from_config!( 55 | "./tests/data/mylibrary.yaml", 56 | "yaml" 57 | )?; 58 | Ok(()) 59 | } 60 | // Unit test for the `macro_create_directories!()` macro. 61 | #[test] 62 | fn test_macro_create_directories() { 63 | let result = macro_create_directories!("./target/tmp"); 64 | match result { 65 | Ok(()) => println!("Directory created successfully!"), 66 | Err(err) => println!("Error creating directory: {}", err), 67 | } 68 | let _ = std::fs::remove_dir_all("./target/tmp"); 69 | } 70 | // Unit test for the `macro_generate_from_csv!()` macro. 71 | #[test] 72 | fn test_macro_generate_from_csv() -> Result<(), String> { 73 | macro_generate_from_csv!("./tests/data/mylibrary.csv")?; 74 | assert!(Path::new("my_library").exists()); 75 | Ok(()) 76 | } 77 | // Unit test for the `macro_generate_from_json!()` macro. 78 | #[test] 79 | fn test_macro_generate_from_json() -> Result<(), String> { 80 | macro_generate_from_json!("./tests/data/mylibrary.json")?; 81 | assert!(Path::new("my_library").exists()); 82 | Ok(()) 83 | } 84 | // Unit test for the `macro_generate_from_yaml!()` macro. 85 | #[test] 86 | fn test_macro_generate_from_yaml() -> Result<(), String> { 87 | macro_generate_from_yaml!("./tests/data/mylibrary.yaml")?; 88 | assert!(Path::new("my_library").exists()); 89 | Ok(()) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /tests/macros/test_log_macros.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use libmake::macro_log_info; 4 | 5 | struct DateTime { 6 | iso_8601: String, 7 | } 8 | 9 | impl DateTime { 10 | fn new() -> Self { 11 | DateTime { 12 | iso_8601: "2024-05-15T12:34:56Z".to_string(), 13 | } 14 | } 15 | } 16 | 17 | struct Random; 18 | 19 | impl Random { 20 | fn default() -> Self { 21 | Random 22 | } 23 | 24 | fn rand(&mut self) -> u64 { 25 | 42 // Mock random number generator returns a fixed value 26 | } 27 | } 28 | 29 | struct Log { 30 | session_id: String, 31 | iso_8601: String, 32 | level: String, 33 | component: String, 34 | description: String, 35 | format: String, 36 | } 37 | 38 | impl Log { 39 | fn new( 40 | session_id: &str, 41 | iso_8601: &str, 42 | level: &str, 43 | component: &str, 44 | description: &str, 45 | format: &str, 46 | ) -> Self { 47 | Log { 48 | session_id: session_id.to_string(), 49 | iso_8601: iso_8601.to_string(), 50 | level: level.to_string(), 51 | component: component.to_string(), 52 | description: description.to_string(), 53 | format: format.to_string(), 54 | } 55 | } 56 | } 57 | 58 | #[test] 59 | fn test_macro_log_info() { 60 | let log = macro_log_info!( 61 | "INFO", 62 | "TestComponent", 63 | "This is a test log", 64 | "TestFormat" 65 | ); 66 | 67 | assert_eq!(log.session_id, "42"); 68 | assert_eq!(log.iso_8601, "2024-05-15T12:34:56Z"); 69 | assert_eq!(log.level, "INFO"); 70 | assert_eq!(log.component, "TestComponent"); 71 | assert_eq!(log.description, "This is a test log"); 72 | assert_eq!(log.format, "TestFormat"); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tests/macros/test_utility_macros.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use libmake::macro_get_field; 4 | use serde_json::from_reader; 5 | use std::env; 6 | use std::fs::File; 7 | use std::io::Write; 8 | use std::path::Path; 9 | use tempfile::tempdir; 10 | 11 | fn read_file( 12 | file_path: &Path, 13 | f: F, 14 | ) -> Result> 15 | where 16 | F: FnOnce(File) -> Result>, 17 | { 18 | let file = File::open(file_path)?; 19 | f(file) 20 | } 21 | 22 | macro_get_field!(get_field, from_reader); 23 | 24 | #[test] 25 | fn test_macro_get_field_success() { 26 | let dir = tempdir().unwrap(); 27 | let file_path = dir.path().join("test.json"); 28 | 29 | let json_data = r#" 30 | { 31 | "name": "Alice", 32 | "age": 30 33 | } 34 | "#; 35 | 36 | let mut file = File::create(&file_path).unwrap(); 37 | file.write_all(json_data.as_bytes()).unwrap(); 38 | 39 | let result = 40 | get_field(Some(file_path.to_str().unwrap()), "name"); 41 | assert_eq!(result.unwrap(), "Alice"); 42 | 43 | let result = 44 | get_field(Some(file_path.to_str().unwrap()), "age"); 45 | assert_eq!(result.unwrap(), "30"); 46 | } 47 | 48 | #[test] 49 | fn test_macro_get_field_field_not_found() { 50 | let dir = tempdir().unwrap(); 51 | let file_path = dir.path().join("test.json"); 52 | 53 | let json_data = r#" 54 | { 55 | "name": "Alice", 56 | "age": 30 57 | } 58 | "#; 59 | 60 | let mut file = File::create(&file_path).unwrap(); 61 | file.write_all(json_data.as_bytes()).unwrap(); 62 | 63 | let result = 64 | get_field(Some(file_path.to_str().unwrap()), "address"); 65 | assert!(result.is_err()); 66 | assert_eq!( 67 | result.unwrap_err().to_string(), 68 | "Field 'address' not found" 69 | ); 70 | } 71 | 72 | #[test] 73 | fn test_macro_get_field_no_file_path() { 74 | let result = get_field(None, "name"); 75 | assert!(result.is_ok()); 76 | assert_eq!(result.unwrap(), ""); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /tests/mod.rs: -------------------------------------------------------------------------------- 1 | /// This module contains the tests for the `macros` module. 2 | pub mod macros; 3 | 4 | /// This module contains the tests for the `models` module. 5 | pub mod models; 6 | -------------------------------------------------------------------------------- /tests/models/mod.rs: -------------------------------------------------------------------------------- 1 | /// The `test_error_ascii_art` module contains tests for the error_ascii_art module. 2 | pub mod test_error_ascii_art; 3 | 4 | /// The `test_model_params` module contains tests for the model_params module. 5 | pub mod test_model_params; 6 | -------------------------------------------------------------------------------- /tests/models/test_error_ascii_art.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use libmake::models::error_ascii_art::AsciiArtError; 4 | use std::error::Error; 5 | 6 | #[test] 7 | fn test_ascii_art_error_font_load_error() { 8 | let error = AsciiArtError::FontLoadError; 9 | assert_eq!(error.to_string(), "Failed to load FIGfont"); 10 | } 11 | 12 | #[test] 13 | fn test_ascii_art_error_conversion_error() { 14 | let error = AsciiArtError::ConversionError; 15 | assert_eq!( 16 | error.to_string(), 17 | "Failed to convert text to ASCII art" 18 | ); 19 | } 20 | 21 | #[test] 22 | fn test_ascii_art_error_partial_eq() { 23 | let error1 = AsciiArtError::FontLoadError; 24 | let error2 = AsciiArtError::FontLoadError; 25 | let error3 = AsciiArtError::ConversionError; 26 | assert_eq!(error1, error2); 27 | assert_ne!(error1, error3); 28 | } 29 | 30 | #[test] 31 | fn test_ascii_art_error_source() { 32 | let error = AsciiArtError::FontLoadError; 33 | assert!(error.source().is_none()); 34 | } 35 | 36 | #[test] 37 | fn test_ascii_art_error_debug() { 38 | let error = AsciiArtError::FontLoadError; 39 | let debug_output = format!("{:?}", error); 40 | assert_eq!(debug_output, "FontLoadError"); 41 | } 42 | 43 | #[test] 44 | fn test_ascii_art_error_clone() { 45 | let error = AsciiArtError::FontLoadError; 46 | let cloned_error = error; 47 | assert_eq!(error, cloned_error); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests/models/test_model_params.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use libmake::models::model_params::FileGenerationParams; 4 | 5 | #[test] 6 | fn test_file_generation_params_default() { 7 | let params = FileGenerationParams::default_params(); 8 | assert_eq!(params.author, Some("John Smith".to_string())); 9 | assert_eq!(params.build, Some("build.rs".to_string())); 10 | assert_eq!( 11 | params.categories, 12 | Some( 13 | "[\"category1\",\"category2\",\"category3\"]" 14 | .to_string() 15 | ) 16 | ); 17 | assert_eq!( 18 | params.description, 19 | Some("A Rust library for doing cool things".to_string()) 20 | ); 21 | assert_eq!( 22 | params.documentation, 23 | Some("https://docs.rs/my_library".to_string()) 24 | ); 25 | assert_eq!(params.edition, Some("2021".to_string())); 26 | assert_eq!( 27 | params.email, 28 | Some("john.smith@example.com".to_string()) 29 | ); 30 | assert_eq!( 31 | params.homepage, 32 | Some("https://my_library.rs".to_string()) 33 | ); 34 | assert_eq!( 35 | params.keywords, 36 | Some("[\"rust\",\"library\",\"cool\"]".to_string()) 37 | ); 38 | assert_eq!(params.license, Some("MIT".to_string())); 39 | assert_eq!(params.name, Some("my_library".to_string())); 40 | assert_eq!(params.output, Some("my_library".to_string())); 41 | assert_eq!(params.readme, Some("README.md".to_string())); 42 | assert_eq!( 43 | params.repository, 44 | Some("https://github.com/example/my_library".to_string()) 45 | ); 46 | assert_eq!(params.rustversion, Some("1.60".to_string())); 47 | assert_eq!(params.version, Some("0.1.0".to_string())); 48 | assert_eq!( 49 | params.website, 50 | Some("https://example.com/john-smith".to_string()) 51 | ); 52 | } 53 | 54 | #[test] 55 | fn test_file_generation_params_new() { 56 | let params = FileGenerationParams::new(); 57 | assert_eq!(params.author, Some("John Smith".to_string())); 58 | assert_eq!(params.build, Some("build.rs".to_string())); 59 | assert_eq!( 60 | params.categories, 61 | Some( 62 | "[\"category1\",\"category2\",\"category3\"]" 63 | .to_string() 64 | ) 65 | ); 66 | assert_eq!( 67 | params.description, 68 | Some("A Rust library for doing cool things".to_string()) 69 | ); 70 | assert_eq!( 71 | params.documentation, 72 | Some("https://docs.rs/my_library".to_string()) 73 | ); 74 | assert_eq!(params.edition, Some("2021".to_string())); 75 | assert_eq!( 76 | params.email, 77 | Some("john.smith@example.com".to_string()) 78 | ); 79 | assert_eq!( 80 | params.homepage, 81 | Some("https://my_library.rs".to_string()) 82 | ); 83 | assert_eq!( 84 | params.keywords, 85 | Some("[\"rust\",\"library\",\"cool\"]".to_string()) 86 | ); 87 | assert_eq!(params.license, Some("MIT".to_string())); 88 | assert_eq!(params.name, Some("my_library".to_string())); 89 | assert_eq!(params.output, Some("my_library".to_string())); 90 | assert_eq!(params.readme, Some("README.md".to_string())); 91 | assert_eq!( 92 | params.repository, 93 | Some("https://github.com/example/my_library".to_string()) 94 | ); 95 | assert_eq!(params.rustversion, Some("1.60".to_string())); 96 | assert_eq!(params.version, Some("0.1.0".to_string())); 97 | assert_eq!( 98 | params.website, 99 | Some("https://example.com/john-smith".to_string()) 100 | ); 101 | } 102 | 103 | #[test] 104 | fn test_file_generation_params_from_args_missing_arg_name() { 105 | let args_str = "\"Jane Doe\" --email \"jane.doe@example.com\""; 106 | let result = FileGenerationParams::from_args(args_str); 107 | assert!(result.is_err()); 108 | assert_eq!( 109 | result.unwrap_err(), 110 | "Missing argument value".to_string() 111 | ); 112 | } 113 | 114 | #[test] 115 | fn test_file_generation_params_from_args_missing_arg_value() { 116 | let args_str = "--author \"Jane Doe\" --email"; 117 | let result = FileGenerationParams::from_args(args_str); 118 | assert!(result.is_err()); 119 | assert_eq!( 120 | result.unwrap_err(), 121 | "Missing argument value".to_string() 122 | ); 123 | } 124 | 125 | #[test] 126 | fn test_deserialize_name() { 127 | let name = "\"my_project\""; 128 | let deserialized_name: Option = 129 | serde_json::from_str(name).unwrap(); 130 | assert_eq!(deserialized_name, Some("my_project".to_string())); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /tests/test_cli.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use libmake::cli::{build, create_arg}; 4 | 5 | #[test] 6 | fn test_build_manual_subcommand() { 7 | let matches = build(); 8 | assert!(matches.is_ok()); 9 | } 10 | 11 | #[test] 12 | fn test_create_arg() { 13 | // Test case 1: Create an argument with all fields 14 | let arg_info = ( 15 | "name", 16 | Some("default"), 17 | "help message", 18 | 'n', 19 | "name", 20 | "NAME", 21 | ); 22 | let arg = create_arg(arg_info); 23 | assert_eq!(arg.get_id(), "name"); 24 | assert_eq!(arg.get_help().unwrap().to_string(), "help message"); 25 | assert_eq!(arg.get_short().unwrap(), 'n'); 26 | assert_eq!(arg.get_long().unwrap(), "name"); 27 | 28 | // Test case 2: Create an argument without a default value 29 | let arg_info = 30 | ("name", None, "help message", 'n', "name", "NAME"); 31 | let arg = create_arg(arg_info); 32 | assert_eq!(arg.get_id(), "name"); 33 | assert_eq!(arg.get_help().unwrap().to_string(), "help message"); 34 | assert_eq!(arg.get_short().unwrap(), 'n'); 35 | assert_eq!(arg.get_long().unwrap(), "name"); 36 | 37 | // Test case 3: Create an argument with only required fields 38 | let arg_info = ("name", None, "", 'n', "name", "NAME"); 39 | let arg = create_arg(arg_info); 40 | assert_eq!(arg.get_id(), "name"); 41 | assert_eq!(arg.get_short().unwrap(), 'n'); 42 | assert_eq!(arg.get_long().unwrap(), "name"); 43 | 44 | // Test case 4: Create an argument with a multi-word long flag 45 | let arg_info = 46 | ("name", None, "help message", 'n', "long-flag", "NAME"); 47 | let arg = create_arg(arg_info); 48 | assert_eq!(arg.get_long().unwrap(), "long-flag"); 49 | 50 | // Test case 5: Argument with an empty help message 51 | let arg_info = ( 52 | "name", None, "", // Empty help message 53 | 'n', "name", "NAME", 54 | ); 55 | let arg = create_arg(arg_info); 56 | 57 | // Updated assertion 58 | assert!(arg.get_help().is_some()); // Help should be set, even if empty 59 | 60 | // Optionally, depending on the implementation of StyledStr: 61 | assert_eq!(arg.get_help().unwrap().to_string(), ""); // Check if the help string is indeed empty 62 | 63 | // Test case 6: Long argument name 64 | let arg_info = ( 65 | "very-long-argument-name", 66 | None, 67 | "help", 68 | 'v', 69 | "very-long-argument-name", 70 | "NAME", 71 | ); 72 | let arg = create_arg(arg_info); 73 | assert_eq!(arg.get_id(), "very-long-argument-name"); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tests/test_utils.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | 4 | use libmake::utils::{ 5 | get_config_field, get_csv_field, get_json_field, get_yaml_field, 6 | }; 7 | // Unit test for the `get_csv_field()` function. 8 | #[test] 9 | fn test_get_csv_field() { 10 | let file_path = "./tests/data/mylibrary.csv"; 11 | 12 | // Test with valid field index 13 | let field_index = 0; 14 | let expected_value = Some(vec!["Me".to_string()]); 15 | let actual_value = get_csv_field(Some(file_path), field_index); 16 | assert_eq!(expected_value, actual_value); 17 | 18 | // Test with invalid field index 19 | let field_index = 100; 20 | let expected_value = None; 21 | let actual_value = get_csv_field(Some(file_path), field_index); 22 | assert_eq!(expected_value, actual_value); 23 | } 24 | 25 | // Unit test for the `get_csv_fields()` function. 26 | #[test] 27 | fn test_get_csv_fields() { 28 | let file_path = "./tests/data/mylibrary.csv"; 29 | 30 | // Test the function with various input values 31 | assert_eq!( 32 | get_csv_field(Some(file_path), 0), 33 | Some(vec!["Me".to_string()]) 34 | ); 35 | print!("{:?}", get_csv_field(Some(file_path), 0)); 36 | assert_eq!( 37 | get_csv_field(Some(file_path), 1), 38 | Some(vec!["build.rs".to_string()]) 39 | ); 40 | assert_eq!( 41 | get_csv_field(Some(file_path), 2), 42 | Some(vec!["['category 1', 'category 2']".to_string()]) 43 | ); 44 | assert_eq!( 45 | get_csv_field(Some(file_path), 3), 46 | Some(vec!["A library for doing things".to_string()]) 47 | ); 48 | assert_eq!( 49 | get_csv_field(Some(file_path), 4), 50 | Some(vec!["https://lib.rs/crates/my_library".to_string()]) 51 | ); 52 | assert_eq!( 53 | get_csv_field(Some(file_path), 5), 54 | Some(vec!["2021".to_string()]) 55 | ); 56 | assert_eq!( 57 | get_csv_field(Some(file_path), 6), 58 | Some(vec!["test@test.com".to_string()]) 59 | ); 60 | assert_eq!( 61 | get_csv_field(Some(file_path), 7), 62 | Some(vec!["https://test.com".to_string()]) 63 | ); 64 | assert_eq!( 65 | get_csv_field(Some(file_path), 8), 66 | Some(vec!["['keyword1', 'keyword2']".to_string()]) 67 | ); 68 | assert_eq!( 69 | get_csv_field(Some(file_path), 9), 70 | Some(vec!["MIT OR Apache-2.0".to_string()]) 71 | ); 72 | assert_eq!( 73 | get_csv_field(Some(file_path), 10), 74 | Some(vec!["my_library".to_string()]) 75 | ); 76 | assert_eq!( 77 | get_csv_field(Some(file_path), 11), 78 | Some(vec!["my_library".to_string()]) 79 | ); 80 | assert_eq!( 81 | get_csv_field(Some(file_path), 12), 82 | Some(vec!["README.md".to_string()]) 83 | ); 84 | assert_eq!( 85 | get_csv_field(Some(file_path), 13), 86 | Some(vec!["https://github.com/test/test".to_string()]) 87 | ); 88 | assert_eq!( 89 | get_csv_field(Some(file_path), 14), 90 | Some(vec!["1.60".to_string()]) 91 | ); 92 | assert_eq!( 93 | get_csv_field(Some(file_path), 15), 94 | Some(vec!["0.2.6".to_string()]) 95 | ); 96 | assert_eq!( 97 | get_csv_field(Some(file_path), 16), 98 | Some(vec!["https://test.com".to_string()]) 99 | ); 100 | } 101 | 102 | // Unit test for the `get_json_field()` function. 103 | #[test] 104 | fn test_get_json_field_existing() { 105 | let file_path = Some("./tests/data/mylibrary.json"); 106 | let field_name = "name"; 107 | let expected_value = Ok("my_library".to_string()); 108 | let actual_value = get_json_field(file_path, field_name) 109 | .map_err(|err| err.to_string()); 110 | assert_eq!(expected_value, actual_value); 111 | } 112 | 113 | // Unit test for the `get_yaml_field()` function. 114 | #[test] 115 | fn test_get_yaml_field_existing() { 116 | let file_path = Some("./tests/data/mylibrary.yaml"); 117 | let field_name = "description"; 118 | let expected_value = 119 | Ok("A library for doing things".to_string()); 120 | let actual_value = get_yaml_field(file_path, field_name) 121 | .map_err(|err| err.to_string()); 122 | assert_eq!(expected_value, actual_value); 123 | } 124 | 125 | // Unit test for the `get_config_field()` function. 126 | // Unit test for the `get_config_field()` function. 127 | #[test] 128 | fn test_get_config_field_existing() { 129 | let file_path = Some("./tests/data/mylibrary.yaml"); 130 | let field_name = "license"; 131 | let expected_value = "MIT OR Apache-2.0"; 132 | let actual_yaml_value = 133 | get_config_field(file_path, Some("yaml"), field_name) 134 | .unwrap_or_else(|_| { 135 | panic!("Failed to get config field: {}", field_name) 136 | }); 137 | 138 | assert_eq!(expected_value, actual_yaml_value); 139 | 140 | let json_file_path = Some("./tests/data/mylibrary.json"); 141 | let actual_json_value = 142 | get_config_field(json_file_path, Some("json"), field_name) 143 | .map_err(|err| err.to_string()) 144 | .unwrap(); 145 | assert_eq!(expected_value, actual_json_value); 146 | 147 | // Test with an empty file format 148 | let actual_empty_format_value = 149 | get_config_field(file_path, None, field_name) 150 | .map_err(|err| err.to_string()) 151 | .unwrap_err(); 152 | assert_eq!( 153 | actual_empty_format_value, 154 | "File format is not provided" 155 | ); 156 | 157 | // Test with an unknown file format 158 | let actual_unknown_format_value = 159 | get_config_field(file_path, Some("unknown"), field_name) 160 | .map_err(|err| err.to_string()) 161 | .unwrap_err(); 162 | assert_eq!(actual_unknown_format_value, "Unsupported file format: unknown. Supported formats are 'json', 'yaml', and 'ini'."); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /tests/utilities/mod.rs: -------------------------------------------------------------------------------- 1 | /// The `test_directory.rs` module contains tests for the directory module. 2 | pub mod test_directory; 3 | 4 | /// The `test_uuid.rs` module contains tests for the UUID module. 5 | pub mod test_uuid; 6 | -------------------------------------------------------------------------------- /tests/utilities/test_directory.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use libmake::utilities::directory::directory; 4 | use std::fs; 5 | use std::io::Error; 6 | use std::path::Path; 7 | use tempfile::tempdir; 8 | 9 | #[test] 10 | fn test_directory_exists() { 11 | let dir = tempdir().unwrap(); 12 | let path = dir.path().join("logs"); 13 | 14 | fs::create_dir(&path).unwrap(); 15 | let result = directory(&path, "logs"); 16 | assert!(result.is_ok()); 17 | assert_eq!(result.unwrap(), ""); 18 | } 19 | 20 | #[test] 21 | fn test_directory_create() { 22 | let dir = tempdir().unwrap(); 23 | let path = dir.path().join("logs"); 24 | 25 | let result = directory(&path, "logs"); 26 | assert!(result.is_ok()); 27 | assert_eq!(result.unwrap(), ""); 28 | assert!(path.exists()); 29 | } 30 | 31 | #[test] 32 | fn test_directory_not_a_directory() { 33 | let dir = tempdir().unwrap(); 34 | let file_path = dir.path().join("not_a_directory"); 35 | 36 | fs::File::create(&file_path).unwrap(); 37 | let result = directory(&file_path, "not_a_directory"); 38 | assert!(result.is_err()); 39 | assert_eq!(result.unwrap_err(), "❌ Error: not_a_directory is not a directory."); 40 | } 41 | 42 | #[test] 43 | fn test_move_output_directory() { 44 | let dir = tempdir().unwrap(); 45 | let out_dir = dir.path().join("out"); 46 | 47 | fs::create_dir(&out_dir).unwrap(); 48 | let result = move_output_directory("site_name", &out_dir); 49 | assert!(result.is_ok()); 50 | 51 | let public_dir = dir.path().join("public"); 52 | let new_project_dir = public_dir.join("site_name"); 53 | assert!(new_project_dir.exists()); 54 | } 55 | 56 | #[test] 57 | fn test_cleanup_directory() { 58 | let dir = tempdir().unwrap(); 59 | let cleanup_dir = dir.path().join("cleanup"); 60 | 61 | fs::create_dir(&cleanup_dir).unwrap(); 62 | let result = cleanup_directory(&[cleanup_dir.as_path()]); 63 | assert!(result.is_ok()); 64 | assert!(!cleanup_dir.exists()); 65 | } 66 | 67 | #[test] 68 | fn test_create_directory() { 69 | let dir = tempdir().unwrap(); 70 | let create_dir = dir.path().join("create"); 71 | 72 | let result = create_directory(&[create_dir.as_path()]); 73 | assert!(result.is_ok()); 74 | assert!(create_dir.exists()); 75 | } 76 | 77 | #[test] 78 | fn test_truncate_path() { 79 | let path = Path::new("/a/b/c/d/e"); 80 | 81 | let result = truncate(&path, 3); 82 | assert_eq!(result, Some("c/d/e".to_string())); 83 | 84 | let result = truncate(&path, 0); 85 | assert_eq!(result, None); 86 | 87 | let result = truncate(&path, 10); 88 | assert_eq!(result, None); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /tests/utilities/test_uuid.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use libmake::utilities::uuid::generate_unique_string; 4 | use uuid::Uuid; 5 | 6 | #[test] 7 | fn test_generate_unique_string_format() { 8 | let unique_string = generate_unique_string(); 9 | let uuid = Uuid::parse_str(&unique_string); 10 | assert!(uuid.is_ok(), "Generated string is not a valid UUID"); 11 | } 12 | 13 | #[test] 14 | fn test_generate_unique_string_uniqueness() { 15 | let unique_string1 = generate_unique_string(); 16 | let unique_string2 = generate_unique_string(); 17 | assert_ne!(unique_string1, unique_string2, "Generated strings are not unique"); 18 | } 19 | } 20 | --------------------------------------------------------------------------------