From c635d7cc515435ff3a884bd2c4b67d77fb109f87 Mon Sep 17 00:00:00 2001 From: Wessel Tip Date: Sun, 2 Mar 2025 13:01:32 +0000 Subject: [PATCH] feat: Modernize boilerplate --- .editorconfig | 12 +-- .eslintignore | 2 - .eslintrc | 66 ----------------- .github/CODEOWNERS | 2 +- .github/CONTRIBUTING.md | 27 +------ .github/FUNDING.yml | 3 +- .github/ISSUE_TEMPLATE/bug_report.yml | 12 +-- .github/ISSUE_TEMPLATE/config.yml | 7 +- .github/ISSUE_TEMPLATE/feature_request.yml | 6 +- .github/PULL_REQUEST_TEMPLATE.md | 2 - .github/auto_assign.yml | 5 +- .gitignore | 13 ++-- LICENSE | 2 +- README.md | 30 +------- init_repo.py | 86 ++++++++++++++++++++++ lib/libtap.c | 2 +- {include => lib}/libtap.h | 0 lib/macros.h | 24 ++++++ lib/{utils.c => util.c} | 0 include/utils.h => lib/util.h | 1 + makefile | 33 +++++++-- obj/.gitkeep | 1 + out/.gitkeep | 1 + src/main.c | 4 +- test/argp.test.c | 58 +++++++++++++++ test/main.test.c | 42 +++++++++++ test/main.test.h | 7 ++ 27 files changed, 273 insertions(+), 175 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc create mode 100644 init_repo.py rename {include => lib}/libtap.h (100%) create mode 100644 lib/macros.h rename lib/{utils.c => util.c} (100%) rename include/utils.h => lib/util.h (80%) create mode 100644 test/argp.test.c create mode 100644 test/main.test.c create mode 100644 test/main.test.h diff --git a/.editorconfig b/.editorconfig index 57a1fc8..310f9a8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,4 +1,11 @@ +root = true + [*] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true cpp_indent_braces=false cpp_indent_multi_line_relative_to=innermost_parenthesis cpp_indent_within_parentheses=indent @@ -57,8 +64,3 @@ cpp_space_around_assignment_operator=insert cpp_space_pointer_reference_alignment=left cpp_space_around_ternary_operator=insert cpp_wrap_preserve_blocks=one_liners -indent_style = space -indent_size = 2 -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true \ No newline at end of file diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 04c01ba..0000000 --- a/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules/ -dist/ \ No newline at end of file diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 4db8d1e..0000000 --- a/.eslintrc +++ /dev/null @@ -1,66 +0,0 @@ -{ - "env": { - "es6": true, - "amd": true, - "jest": true, - "node": true, - "mongo": true, - "jquery": true, - "browser": true, - "commonjs": true - }, - "parserOptions": { - "ecmaVersion": 9, - "sourceType": "module", - "ecmaFeatures": { - "jsx": true, - "forOf": true, - "spread": true, - "modules": true, - "classes": true, - "generators": true, - "restParams": true, - "regexUFlag": true, - "regexYFlag": true, - "globalReturn": true, - "destructuring": true, - "impliedStrict": true, - "blockBindings": true, - "defaultParams": true, - "octalLiterals": true, - "arrowFunctions": true, - "binaryLiterals": true, - "templateStrings": true, - "superInFunctions": true, - "unicodeCodePointEscapes": true, - "experimentalObjectRestSpread": true, - "objectLiteralShorthandMethods": true, - "objectLiteralComputedProperties": true, - "objectLiteralDuplicateProperties": true, - "objectLiteralShorthandProperties": true - } - }, - "plugins": [], - "rules": { - "semi": "warn", - "indent": [ "off", "error" ], - "strict": "off", - "eqeqeq": "error", - "no-var": "warn", - "no-undef": "warn", - "valid-jsdoc": "warn", - "comma-dangle": "warn", - "no-dupe-args": "warn", - "no-dupe-keys": "warn", - "require-await": "warn", - "spaced-comment": "error", - "space-in-parens": "error", - "no-global-assign": "warn", - "no-duplicate-imports": "error", - "no-dupe-class-members": "error" - }, - "globals": { - "_config": false, - "console": false - } -} diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 471b894..bee82d5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @Wessel +* @{{project.master}} diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 8aeddf1..0706835 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,38 +1,13 @@ # Contributing - - If you wish to contribute to {{project.name}}, feel free to fork the repository and submit a pull request. {{project.linter}} is enforced to correct most typo's you make and keep the code style the same throughout the whole project, so it would be much appreciated if you installed {{project.linter}} to your editor of choice - ## Prerequisites The following prerequisites must be met before installing {{project.name}}: {{setup.prerequisites}} - ## Setup To get ready to work on the codebase, please do the following: @@ -46,4 +21,4 @@ When creating any new functions, please also create unit tests for them in the ` Use the library associated with the project when creating such tests. When modifying existing functions, make sure to test them before making a pull request, this will prevent -anything from breaking on the production environment. \ No newline at end of file +anything from breaking on the production environment. diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index a0960cb..b3be161 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1 @@ -github: wessel -ko_fi: wessel \ No newline at end of file +{{project.funding}} diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 5dcf3b4..01b6643 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,18 +1,12 @@ -# Adapted from https://github.com/discordjs/discord.js/blob/main/.github/ISSUE_TEMPLATE/bug_report.yml name: Bug report description: Report incorrect or unexpected behavior of a package labels: [bug, need repro] body: - # - type: markdown - # attributes: - # value: | - # Use Discord for questions: https://discord.gg/djs - type: dropdown id: package attributes: label: Which part is this bug report for? - options: - - {{tree.parts}} + options: {{tree.parts}} validations: required: true - type: textarea @@ -48,7 +42,7 @@ body: - type: input id: lang-version attributes: - label: {{project.lang}} version + label: '{{project.lang}} version' description: | Which version of {{project.lang}} are you using? validations: @@ -75,4 +69,4 @@ body: label: I have tested this issue on a development release placeholder: d23280c (commit hash) description: | - The issue might already be fixed in a development release or main. This is not required, but helps us greatly. \ No newline at end of file + The issue might already be fixed in a development release or main. This is not required, but helps us greatly. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 678c4a1..a5f5423 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,7 +1,2 @@ blank_issues_enabled: false -# Example entry: -# name: -# url: -# about: -contact_links: - - {{project.contact}} \ No newline at end of file +{{project.contact}} diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 2c78a12..14a0911 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,4 +1,3 @@ -# Adapted from https://github.com/discordjs/discord.js/blob/main/.github/ISSUE_TEMPLATE/feature_request.yml name: Feature request description: Request a new feature labels: [feature request] @@ -11,8 +10,7 @@ body: id: package attributes: label: Which part is this feature request for? - options: - - {{tree.parts}} + options: {{tree.parts}} validations: required: false - type: textarea @@ -39,4 +37,4 @@ body: id: additional-context attributes: label: Other context - description: Any other context, screenshots, or file uploads that help us understand your feature request. \ No newline at end of file + description: Any other context, screenshots, or file uploads that help us understand your feature request. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e73bb19..f35130a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -3,8 +3,6 @@ name: Pull Request about: Propose changes to {{project.name}} title: "[PR] Your changes" labels: pullrequest -assignees: Wessel - --- **Please describe the changes this PR makes and why it should be merged:** diff --git a/.github/auto_assign.yml b/.github/auto_assign.yml index d262d75..3c8d1f2 100644 --- a/.github/auto_assign.yml +++ b/.github/auto_assign.yml @@ -1,5 +1,4 @@ addReviewers: true -reviewers: - - {{project.reviewers}} +reviewers: {{project.reviewers}} numberOfReviewers: 0 -runOnDraft: true \ No newline at end of file +runOnDraft: true diff --git a/.gitignore b/.gitignore index ec6cb9f..acf19a0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,6 @@ +# C build files +**/*.o +**/out/* + +**/tmp/* !.gitkeep - -tmp/ -src/tmp - -node_modules/ - -obj/ -out/ \ No newline at end of file diff --git a/LICENSE b/LICENSE index 05a71ff..b4bba09 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ The MIT License (MIT) -Copyright (c) 2023 Wessel T (https://wessel.gg/) +Copyright (c) {{project.license}} Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 71e71d4..020ea8d 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,12 @@ - > {{project.name}} -[![MIT License](https://img.shields.io/badge/license-MIT-007EC7.svg?style=flat-square)](/LICENSE) {{info.badges}} +[![MIT License](https://img.shields.io/badge/license-MIT-007EC7.svg?style=flat-square)](/LICENSE) {{info.desc}}

- ## Table of contents -{{info.toc}} - diff --git a/init_repo.py b/init_repo.py new file mode 100644 index 0000000..5527d89 --- /dev/null +++ b/init_repo.py @@ -0,0 +1,86 @@ +import os +import yaml +import re +import datetime + +file_types = ['LICENSE', 'CODEOWNERS', '.md', '.yml'] +script_name = os.path.basename(__file__) + +def replace_placeholders(file_path, replacements): + with open(file_path, 'r', encoding='utf-8') as file: + content = file.read() + + for placeholder, replacement in replacements.items(): + content = re.sub(re.escape(placeholder), replacement, content) + + with open(file_path, 'w', encoding='utf-8') as file: + file.write(content) + +def initialize_repository(directory, replacements): + for root, _, files in os.walk(directory): + for file in files: + if file == script_name: + continue + if any(file.endswith(file_type) for file_type in file_types): + file_path = os.path.join(root, file) + replace_placeholders(file_path, replacements) + +def parse_input(prompt): + return [item.strip() for item in input(prompt).split(',')] + +def parse_contact(prompt): + contacts = [] + while True: + print(prompt) + name = input(f"\tName\t\t").strip() + if not name: + break + url = input(f"\tURL\t\t").strip() + about = input(f"\tAbout\t\t").strip() + contacts.append({'name': name, 'url': url, 'about': about}) + return {'contact_links': contacts} + +def parse_funding(prompt): + funding = {} + while True: + print(prompt) + key = input(f"\tKey\t\t").strip() + if not key: + break + value = input(f"\tValue\t\t").strip() + funding[key] = value + + return funding + +def main(): + current_year = str(datetime.datetime.now().year) + + replacements = { + "{{project.name}}": input("Project name\t\t"), + "{{info.desc}}": input("Project Description\t"), + "{{project.master}}": input("Master of the repo\t"), + "{{project.license}}": f"{current_year} " + input('License holder\t\t'), + + "{{tree.parts}}": yaml.dump(parse_input("Parts of the repo\t"), default_flow_style=True), + "{{project.lang}}": input("Language used\t\t"), + "{{project.linter}}": input("Linter used\t\t"), + + "{{setup.prerequisites}}": input("Prerequisites\t\t"), + "{{setup.install}}": input("Install command\t\t"), + "{{setup.test}}": input("Test command\t\t"), + + "{{project.logo}}": input("Project logo URL\t"), + "{{project.funding}}": yaml.dump(parse_funding("Funding methods\t\t"), default_flow_style=True), + "{{project.contact}}": yaml.dump(parse_contact("Contact information\t"), default_flow_style=False), + "{{project.reviewers}}": yaml.dump(parse_input("Auto-assign users (x,y)\t"), default_flow_style=True) + } + + directory = input("Initialize directory\t") or '.' + initialize_repository(directory, replacements) + + delete = input("Delete this script? (Y/n)\t") or "y" + if delete.lower() == "y": + os.remove(__file__) + +if __name__ == "__main__": + main() diff --git a/lib/libtap.c b/lib/libtap.c index 2a7ba57..897672b 100644 --- a/lib/libtap.c +++ b/lib/libtap.c @@ -12,7 +12,7 @@ This file is licensed under the LGPL #include #include #include -#include "tap.h" +#include "libtap.h" static int expected_tests = NO_PLAN; static int failed_tests; diff --git a/include/libtap.h b/lib/libtap.h similarity index 100% rename from include/libtap.h rename to lib/libtap.h diff --git a/lib/macros.h b/lib/macros.h new file mode 100644 index 0000000..a7f9a84 --- /dev/null +++ b/lib/macros.h @@ -0,0 +1,24 @@ +/* macros.h */ +#include + +#ifndef MACROS_H +#define MACROS_H + +enum DEBUG_STATE { INACTIVE, ACTIVE }; + +#ifndef __DEBUG__ + #define __DEBUG__ ACTIVE +#endif + +/** @brief Prints to the console only if DEBUG = 1 **/ +#define dbg(fmt, ...) do { \ + if (__DEBUG__ == ACTIVE) \ + fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, __VA_ARGS__); \ +} while (0) + +#define dbg_no_info(fmt, ...) do { \ + if (__DEBUG__ == ACTIVE) \ + fprintf(stderr, fmt, __VA_ARGS__); \ +} while (0) + +#endif diff --git a/lib/utils.c b/lib/util.c similarity index 100% rename from lib/utils.c rename to lib/util.c diff --git a/include/utils.h b/lib/util.h similarity index 80% rename from include/utils.h rename to lib/util.h index 3f49bbd..aeb641c 100644 --- a/include/utils.h +++ b/lib/util.h @@ -1,3 +1,4 @@ +/* util.h */ #ifndef UTILS_H #define UTILS_H diff --git a/makefile b/makefile index 152cfc9..4164de0 100644 --- a/makefile +++ b/makefile @@ -7,15 +7,21 @@ LIB_DIR := lib OBJ_DIR := obj OUT_DIR := out INC_DIR := include +TST_DIR := test # Map all object and source files -SRC_FILES := $(wildcard $(SRC_DIR)/*.c) $(wildcard $(LIB_DIR)/*.c) -OBJ_FILES := $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(SRC_FILES)) +SRC_FILES := $(wildcard $(SRC_DIR)/**/*.c) $(wildcard $(LIB_DIR)/**/*.c) +OBJ_FILES := $(patsubst $(SRC_DIR)/**/%.c,$(OBJ_DIR)/%.o,$(SRC_FILES)) + +TST_FILES := $(wildcard $(TST_DIR)/*.c) $(wildcard $(LIB_DIR)/*.c) +OBJ_TST_FILES := $(patsubst $(TST_DIR)/%.c,$(OBJ_DIR)/%.o,$(TST_FILES)) # All optional libs and Cflags to append to the final command -LIBS := -lm +LIBS := CFLAGS := -I$(INC_DIR) -BUILDFLAGS := -Wall -Wextra -Wconversion +DEBUGFLAGS := +BUILDFLAGS := +WARNFLAGS := -Wall -Wextra -Wconversion # Special and default commands .PHONY: clean help @@ -25,6 +31,9 @@ BUILDFLAGS := -Wall -Wextra -Wconversion $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(CC) -c -o $@ $< +$(OBJ_DIR)/%.o: $(TST_DIR)/%.c + $(CC) -c -o $@ $< + ## All make commands ## help: ## Lists all commands @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' @@ -33,10 +42,20 @@ clean: ## Clean up all object files and executables rm -f $(OBJ_DIR)/*.o $(OUT_DIR)/* dev: $(OBJ_FILES) ## Build, run and debug the project - $(CC) -o $(OUT_DIR)/$@ $^ $(CFLAGS) $(LIBS) && strace ./out/dev + $(CC) -o $(OUT_DIR)/$@ $^ $(CFLAGS) $(LIBS) $(DEBUGFLAGS) && ./out/dev run: $(OBJ_FILES) ## Build and run the project - $(CC) -o $(OUT_DIR)/$@ $^ $(CFLAGS) $(LIBS) && ./out/run + $(CC) -o $(OUT_DIR)/$@ $^ $(CFLAGS) $(LIBS) $(WARNFLAGS) && ./out/run prod: $(OBJ_FILES) ## Build the project - $(CC) -o $(OUT_DIR)/$@ $^ $(CFLAGS) $(BUILDFLAGS) $(LIBS) + $(CC) -o $(OUT_DIR)/$@ $^ $(CFLAGS) $(LIBS) $(BUILDFLAGS) $(WARNFLAGS) + +test: $(OBJ_TST_FILES) ## Build tests and run them + $(CC) -o $(OUT_DIR)/$@ $^ $(CFLAGS) $(LIBS) && ./out/test \ + --port 6060 --timeout 500 + +valgrind: $(OBJ_FILES) ## Build the project and run with Valgrind + $(CC) -o $(OUT_DIR)/$@ $^ $(CFLAGS) $(LIBS) && valgrind ./out/valgrind + +strace: $(OBJ_FILES) ## Build the project and run with strace + $(CC) -o $(OUT_DIR)/$@ $^ $(CFLAGS) $(LIBS) && strace ./out/strace diff --git a/obj/.gitkeep b/obj/.gitkeep index e69de29..5432cba 100644 --- a/obj/.gitkeep +++ b/obj/.gitkeep @@ -0,0 +1 @@ +Contains object files generated by make \ No newline at end of file diff --git a/out/.gitkeep b/out/.gitkeep index e69de29..a47c6e1 100644 --- a/out/.gitkeep +++ b/out/.gitkeep @@ -0,0 +1 @@ +Contains executables generated by make \ No newline at end of file diff --git a/src/main.c b/src/main.c index 1415dea..b75c16d 100644 --- a/src/main.c +++ b/src/main.c @@ -6,9 +6,7 @@ #include #include -#include "../include/utils.h" -/* Libtap for tests */ -#include "../include/libtap.h" +#include "../../lib/util.h" int main(int argc, char *argv[], char *env[]) { return 0; diff --git a/test/argp.test.c b/test/argp.test.c new file mode 100644 index 0000000..c5da34d --- /dev/null +++ b/test/argp.test.c @@ -0,0 +1,58 @@ +/* argp.test.c */ +#include + +#include "../lib/libtap.h" +#include "../lib/macros.h" + +// Define the structure to store the arguments +struct arguments { + int port; + int timeout; +}; + +// Define the argument parser +static struct argp_option options[] = { + {"port", 'p', "PORT", 0, "Port number"}, + {"timeout", 't', "TIMEOUT", 0, "Timeout in seconds"}, + {0} +}; + +static error_t parse_opt(int key, char* arg, struct argp_state* state) { + struct arguments* arguments = state->input; + switch (key) { + case 'p': + arguments->port = atoi(arg); + break; + case 't': + arguments->timeout = atoi(arg); + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = { options, parse_opt, 0, 0 }; + + + +void run_argp_tests(int argc, char* argv[], char* env[]) { + + printf("\033[0;35m--Tests for parsing CL args--\033[0;0m\n"); + + /* Unit tests for parsing console arguments */ + struct arguments args; + + // Set default values for the arguments + args.port = 8080; + args.timeout = 10; + dbg("defaults(Arguments { port: 8080, timeout: 10 })\n", NULL); + + // Parse the arguments + argp_parse(&argp, argc, argv, 0, 0, &args); + dbg("parsed(Arguments { port: %d, timeout: %d })\n", args.port, args.timeout); + + ok(args.port == 6060, "Arg `port` is `6060`"); + ok(args.timeout == 500, "Arg `timeout` is `500`"); + +} \ No newline at end of file diff --git a/test/main.test.c b/test/main.test.c new file mode 100644 index 0000000..76fa97f --- /dev/null +++ b/test/main.test.c @@ -0,0 +1,42 @@ +/* main.test.c */ +#include +#include +#include + +#include "main.test.h" +#include "../lib/libtap.h" +#include "../lib/macros.h" + +int main(int argc, char* argv[], char* env[]) { + srand(time(NULL)); + + /* Debug log: argv variables */ + dbg("argc:\t%d\n", argc); + dbg("argv:\t", NULL); + for (int i = 0; i < argc; i++) dbg_no_info("%s ", argv[i]); + dbg_no_info("\n", NULL); + + /* Debug log: env variables */ + dbg("env:\t", NULL); + + int colors[] = { 31, 32, 33, 34, 35 }; + int colors_len = 4; + int colors_i = 0; + + for (int i = 0; env[i] != NULL; i++) { + dbg_no_info("\033[0;%dm%s\033[0;0m ", colors[colors_i], env[i]); + colors_i = colors_i == colors_len ? 0 : colors_i + 1; + } + + dbg_no_info("\n", NULL); + + /* Initialize unit tests */ + plan(2); + + dbg("Running `run_argp_tests`\n", NULL); + run_argp_tests(argc, argv, env); + + done_testing(); + + return 0; +} diff --git a/test/main.test.h b/test/main.test.h new file mode 100644 index 0000000..85384c5 --- /dev/null +++ b/test/main.test.h @@ -0,0 +1,7 @@ +/* main.test.h */ +#ifndef TESTS_H +#define TESTS_H + +void run_argp_tests(int argc, char* argv[], char* env[]); + +#endif \ No newline at end of file