Compare commits
21 Commits
4bee3f28df
...
master
Author | SHA1 | Date | |
---|---|---|---|
eca51af5ea | |||
30ecc9b87c | |||
5dbf86164a | |||
84f36247a8 | |||
06f92a3228 | |||
cecde4478d | |||
5e34464718 | |||
c6ce3bbd23 | |||
1118341f26 | |||
bc7e232aeb | |||
6ca7201203 | |||
8d42484863 | |||
673d0297aa | |||
6dbf32a5b1 | |||
b9d2589f8b | |||
5af72b4f99 | |||
3a7e2f2af8 | |||
d14c0a725c | |||
53f66d440c | |||
dfb26e14c9 | |||
afc31abe30 |
57
README.md
Normal file
57
README.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# Coding Tools
|
||||||
|
Tools that I wrote to help me code faster and more efficiently.
|
||||||
|
All of these require `python>=3.6`.
|
||||||
|
|
||||||
|
## [Ucompile](ucompile)
|
||||||
|
Pronounced "you compile", stands for "University Compiler". It is a simple script that compiles and runs programs in one line. It also automatically takes all `.in` files in the directory and feeds them to the program. It is useful for competitive programming and for testing programs with multiple test cases.
|
||||||
|
|
||||||
|
Currently supports:
|
||||||
|
- C (`.c`)
|
||||||
|
- Python (`.py`) (with Python 3 and PyPy3)
|
||||||
|
- Java (`.java`)
|
||||||
|
- Haskell (`.hs`)
|
||||||
|
|
||||||
|
Optional arguments:
|
||||||
|
- `-o` checks the output of the program against the `.out` files in the directory
|
||||||
|
- `-v, --verbose` prints the output of the program
|
||||||
|
- `-a` uses an alternative compiler (e.g. `mvn` instead of `javac`)
|
||||||
|
- `-t, --tests` specifies a test case folder (default is `.`, the current directory)
|
||||||
|
- `-T, --time` prints the time taken to run the program
|
||||||
|
|
||||||
|
The program is integrated with [temmies](https://github.com/Code-For-Groningen/temmies) for automatic [Themis](https://themis.housing.rug.nl/) submission.
|
||||||
|
|
||||||
|
## [unifytex](unifytex)
|
||||||
|
|
||||||
|
is a script designed to automate the process of generating separate LaTeX include files for `.tex` files in a directory, making it easier to manage large LaTeX projects. It recursively scans a specified directory and creates consolidated `.tex` files that include all the LaTeX files within each subdirectory.
|
||||||
|
|
||||||
|
(EXAMPLE) If the directory structure is:
|
||||||
|
```
|
||||||
|
/project
|
||||||
|
├── section1
|
||||||
|
│ ├── intro.tex
|
||||||
|
│ ├── methods.tex
|
||||||
|
├── section2
|
||||||
|
│ ├── results.tex
|
||||||
|
│ ├── discussion.tex
|
||||||
|
```
|
||||||
|
Running:
|
||||||
|
```bash
|
||||||
|
python3 unifytex.py /project
|
||||||
|
```
|
||||||
|
Will create:
|
||||||
|
```
|
||||||
|
/project/consolidated
|
||||||
|
├── section1.tex (contains \input{section1/intro.tex} and \input{section1/methods.tex})
|
||||||
|
├── section2.tex (contains \input{section2/results.tex} and \input{section2/discussion.tex})
|
||||||
|
```
|
||||||
|
This allows you to include an entire section in your main LaTeX document with:
|
||||||
|
```latex
|
||||||
|
\input{consolidated/section1.tex}
|
||||||
|
```
|
||||||
|
|
||||||
|
## [flatcher](flatcher)
|
||||||
|
|
||||||
|
Flask + Catcher = Flatcher. A simple script that runs a Flask server and catches all requests to a specified port, detailing the request method, path, and headers. Useful for debugging and testing webhooks.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> This script requires Flask to be installed. You can install it with `pip install Flask`.
|
19
flatcher
Executable file
19
flatcher
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
from flask import Flask, request
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route('/', defaults={'path': ''}, methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'])
|
||||||
|
@app.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'])
|
||||||
|
def capture_request(path):
|
||||||
|
"""
|
||||||
|
This route captures all requests, regardless of method or path.
|
||||||
|
"""
|
||||||
|
print(f"Request Path: {request.path}")
|
||||||
|
print(f"Request Method: {request.method}")
|
||||||
|
print(f"Request Headers: {dict(request.headers)}")
|
||||||
|
print(f"Request Body: {request.get_data(as_text=True)}")
|
||||||
|
return "Request captured and printed to the console!", 200
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run(debug=True, host='0.0.0.0', port=5000)
|
205
ucompile
205
ucompile
@ -4,37 +4,79 @@ import os
|
|||||||
from glob import glob
|
from glob import glob
|
||||||
import subprocess
|
import subprocess
|
||||||
from colorama import Fore, Style
|
from colorama import Fore, Style
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
def check_dependencies() -> None:
|
def check_dependencies() -> None:
|
||||||
# Necessary commands list
|
# Necessary commands list
|
||||||
commands = ["astyle", "gcc", "ghc", "java", "javac", "mvn", "python3"]
|
commands = ["astyle", "gcc", "ghc", "java", "javac", "mvn", "python3"]
|
||||||
|
|
||||||
for command in commands:
|
for command in commands:
|
||||||
if os.system(f"which {command} > /dev/null") != 0:
|
if os.system(f"which {command} > /dev/null") != 0:
|
||||||
print(f"{Fore.RED}Error: {command} not found{Style.RESET_ALL}")
|
print(f"{Fore.RED}WARNING: {command} not found{Style.RESET_ALL}")
|
||||||
return
|
return
|
||||||
|
|
||||||
def run_input_cases(program, verbose, output=False, tests_dir="."):
|
|
||||||
input_files = glob(os.path.join(tests_dir, "*.in"))
|
def run_input_cases(program, args) -> bool:
|
||||||
|
verbose = args.verbose
|
||||||
|
output = args.output
|
||||||
|
tests_dir = args.tests_dir if args.tests_dir else "."
|
||||||
|
time_flag = args.time
|
||||||
|
|
||||||
|
input_files = sorted(glob(os.path.join(tests_dir, "*.in")), key=os.path.getmtime)
|
||||||
|
|
||||||
|
passed = True
|
||||||
if len(input_files) < 1:
|
if len(input_files) < 1:
|
||||||
return os.system(program)
|
if time_flag:
|
||||||
|
start_time = time.perf_counter()
|
||||||
|
result = subprocess.run(
|
||||||
|
program,
|
||||||
|
shell=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
universal_newlines=True,
|
||||||
|
)
|
||||||
|
end_time = time.perf_counter()
|
||||||
|
elapsed_time = end_time - start_time
|
||||||
|
print(result.stdout.strip())
|
||||||
|
print(f"Time taken: {elapsed_time:.4f} seconds")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
return os.system(program)
|
||||||
|
|
||||||
for input_file in input_files:
|
for input_file in input_files:
|
||||||
print(f"Running {input_file}")
|
print(f"Running {input_file}")
|
||||||
end_command = f"{program} < {input_file}"
|
end_command = f"{program} < {input_file}"
|
||||||
|
|
||||||
with open(input_file, 'r') as f:
|
with open(input_file, "r") as f:
|
||||||
input_data = f.read()
|
input_data = f.read()
|
||||||
|
|
||||||
out_file = input_file.replace(".in", ".out")
|
out_file = input_file.replace(".in", ".out")
|
||||||
expected_output = None
|
expected_output = None
|
||||||
if os.path.exists(out_file):
|
if os.path.exists(out_file):
|
||||||
with open(out_file, 'r') as f:
|
with open(out_file, "r") as f:
|
||||||
expected_output = f.read()
|
expected_output = f.read()
|
||||||
|
|
||||||
result = subprocess.run(end_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
|
if time_flag:
|
||||||
|
start_time = time.perf_counter()
|
||||||
|
result = subprocess.run(
|
||||||
|
end_command,
|
||||||
|
shell=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
universal_newlines=True,
|
||||||
|
)
|
||||||
|
end_time = time.perf_counter()
|
||||||
|
elapsed_time = end_time - start_time
|
||||||
|
else:
|
||||||
|
result = subprocess.run(
|
||||||
|
end_command,
|
||||||
|
shell=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
universal_newlines=True,
|
||||||
|
)
|
||||||
|
|
||||||
program_output = result.stdout
|
program_output = result.stdout
|
||||||
|
|
||||||
if verbose and not output:
|
if verbose and not output:
|
||||||
@ -49,7 +91,6 @@ def run_input_cases(program, verbose, output=False, tests_dir="."):
|
|||||||
print(program_output.strip())
|
print(program_output.strip())
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
|
|
||||||
if output:
|
if output:
|
||||||
if expected_output is not None:
|
if expected_output is not None:
|
||||||
# Compare the outputs
|
# Compare the outputs
|
||||||
@ -57,13 +98,24 @@ def run_input_cases(program, verbose, output=False, tests_dir="."):
|
|||||||
print("✅")
|
print("✅")
|
||||||
else:
|
else:
|
||||||
print("❌")
|
print("❌")
|
||||||
|
passed = False
|
||||||
# green expected output and red program output
|
# green expected output and red program output
|
||||||
print(f"{Fore.GREEN}Expected output:{Style.RESET_ALL}")
|
# print(f"{Fore.GREEN}Expected output:{Style.RESET_ALL}")
|
||||||
print(expected_output)
|
# print(expected_output)
|
||||||
print(f"{Fore.RED}Program output:{Style.RESET_ALL}")
|
# print(f"{Fore.RED}Program output:{Style.RESET_ALL}")
|
||||||
print(program_output.strip())
|
# print(program_output.strip())
|
||||||
|
# print a diff
|
||||||
|
print(f"{Fore.YELLOW}Diff:{Style.RESET_ALL}")
|
||||||
|
# temporary file to store program output
|
||||||
|
with open("temp", "w") as f:
|
||||||
|
f.write(program_output)
|
||||||
|
os.system(f"diff -u {out_file} - < temp")
|
||||||
|
os.remove("temp")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print(f"{Fore.YELLOW}Expected output file not found; cannot compare outputs.{Style.RESET_ALL}")
|
print(
|
||||||
|
f"{Fore.YELLOW}Expected output file not found; cannot compare outputs.{Style.RESET_ALL}"
|
||||||
|
)
|
||||||
if not verbose:
|
if not verbose:
|
||||||
print("Program output:")
|
print("Program output:")
|
||||||
print(program_output.strip())
|
print(program_output.strip())
|
||||||
@ -71,66 +123,119 @@ def run_input_cases(program, verbose, output=False, tests_dir="."):
|
|||||||
if not verbose:
|
if not verbose:
|
||||||
print(program_output.strip())
|
print(program_output.strip())
|
||||||
|
|
||||||
|
if time_flag:
|
||||||
|
print("=====")
|
||||||
|
print(f"⏳: {elapsed_time:.4f} s")
|
||||||
|
|
||||||
print("-----------")
|
print("-----------")
|
||||||
return
|
return passed
|
||||||
|
|
||||||
def python_compile(file_name, verbose=False, tests_dir="."):
|
|
||||||
run_input_cases("python3 " + file_name, verbose, tests_dir=tests_dir)
|
|
||||||
return
|
|
||||||
|
|
||||||
def java_compile(file_name, maven=False, verbose=False, tests_dir="."):
|
def python_compile(file_name, args) -> bool:
|
||||||
if maven:
|
passed = None
|
||||||
|
try:
|
||||||
|
if os.system("which pypy3 &> /dev/null") == 0:
|
||||||
|
print(f"{Fore.LIGHTMAGENTA_EX}Using pypy3{Style.RESET_ALL}")
|
||||||
|
return run_input_cases("pypy3 " + file_name, args)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
print(f"{Fore.MAGENTA}WARNING: pypy3 not found, using python3 instead{Style.RESET_ALL}")
|
||||||
|
return run_input_cases("python3 " + file_name, args)
|
||||||
|
|
||||||
|
def java_compile(file_name, args):
|
||||||
|
if args.alternative:
|
||||||
os.system("mvn clean verify")
|
os.system("mvn clean verify")
|
||||||
os.system("java -jar target/*.jar")
|
run_input_cases("java -jar target/*.jar", args)
|
||||||
return
|
return
|
||||||
os.system("javac " + file_name)
|
os.system("javac " + file_name)
|
||||||
run_input_cases("java " + file_name[:file_name.rfind(".")], verbose, tests_dir=tests_dir)
|
class_name = os.path.splitext(file_name)[0]
|
||||||
|
run_input_cases("java " + class_name, args)
|
||||||
return
|
return
|
||||||
|
|
||||||
def haskell_compile(file_name, verbose=False, tests_dir="."):
|
|
||||||
|
def haskell_compile(file_name, args):
|
||||||
os.system("ghc -O2 " + file_name + " -o program")
|
os.system("ghc -O2 " + file_name + " -o program")
|
||||||
run_input_cases("./program", verbose, tests_dir=tests_dir)
|
return run_input_cases("./program", args)
|
||||||
|
|
||||||
|
|
||||||
|
def c_compile(file_name, args):
|
||||||
|
# Style the code in Meijster's way
|
||||||
|
# os.system("astyle -A2s2cxgk3W3xbj " + file_name)
|
||||||
|
# If you want
|
||||||
|
|
||||||
|
# stop if compilation fails
|
||||||
|
if os.system(
|
||||||
|
"gcc -Wall -pedantic --std=c99 -g -o program -pthread -lm -Wno-unused-result " + file_name
|
||||||
|
):
|
||||||
|
return False
|
||||||
|
|
||||||
|
run_input_cases("./program", args)
|
||||||
return
|
return
|
||||||
|
|
||||||
def c_compile(file_name, verbose=False, output=False, tests_dir="."):
|
|
||||||
# Style the code in Meijster's way
|
|
||||||
os.system("astyle -A2s2cxgk3W3xbj " + file_name)
|
|
||||||
os.system("gcc -Wall -pedantic --std=c99 -g -o program -lm -Wno-unused-result " + file_name)
|
|
||||||
run_input_cases("./program", verbose, output, tests_dir=tests_dir)
|
|
||||||
return
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
SUPPORTED_LANGS = [".c", ".py", ".java", ".hs"]
|
SUPPORTED_LANGS = {
|
||||||
|
".c": c_compile,
|
||||||
|
".py": python_compile,
|
||||||
|
".java": java_compile,
|
||||||
|
".hs": haskell_compile,
|
||||||
|
}
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
prog='UCompiler',
|
prog="UCompiler", description="Compiles based on language", epilog="LOL"
|
||||||
description='Compiles based on language',
|
)
|
||||||
epilog='LOL')
|
|
||||||
parser.add_argument("filename", metavar="<file>", type=str, help="File to compile")
|
parser.add_argument("filename", metavar="<file>", type=str, help="File to compile")
|
||||||
parser.add_argument("-v", "--verbose", action="store_true", default=False, help="Prints input and output")
|
parser.add_argument(
|
||||||
parser.add_argument("-a", "--alternative", action="store_true", default=False, help="Uses alternative compiler to compile")
|
"-v",
|
||||||
parser.add_argument("-o", "--output", action="store_true", default=False, help="Checks diff for each .in file with .out file")
|
"--verbose",
|
||||||
parser.add_argument("-t", "--tests", metavar="<path>", type=str, help="Directory to run tests")
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help="Prints input and output",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-a",
|
||||||
|
"--alternative",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help="Uses alternative compiler to compile",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-o",
|
||||||
|
"--output",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help="Checks diff for each .in file with .out file",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-t", "--tests", metavar="<path>", type=str, help="Directory to run tests"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-T",
|
||||||
|
"--time",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help="Prints time taken to run each test case",
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
file_name = args.filename
|
file_name = args.filename
|
||||||
file_ext = file_name[file_name.rfind("."):]
|
file_ext = os.path.splitext(file_name)[1]
|
||||||
if file_ext not in SUPPORTED_LANGS:
|
if file_ext not in SUPPORTED_LANGS:
|
||||||
print("Unsupported language")
|
print("Unsupported language")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Use the specified tests directory or default to current directory
|
args.tests_dir = args.tests if args.tests else "."
|
||||||
tests_dir = args.tests if args.tests else "."
|
|
||||||
|
if not SUPPORTED_LANGS[file_ext](file_name, args): # don't do submit dialogue if failed
|
||||||
|
return
|
||||||
|
|
||||||
|
temmies_check = os.path.join(os.path.dirname(file_name), ".temmies")
|
||||||
|
if os.path.exists(temmies_check):
|
||||||
|
if input("🎉✨ -- Submit? (y/N): ") == "y":
|
||||||
|
os.system("temmies submit")
|
||||||
|
|
||||||
if file_ext == ".c":
|
|
||||||
c_compile(file_name, args.verbose, args.output, tests_dir=tests_dir)
|
|
||||||
elif file_ext == ".py":
|
|
||||||
python_compile(file_name, args.verbose, tests_dir=tests_dir)
|
|
||||||
elif file_ext == ".java":
|
|
||||||
java_compile(file_name, args.alternative, args.verbose, tests_dir=tests_dir)
|
|
||||||
elif file_ext == ".hs":
|
|
||||||
haskell_compile(file_name, args.verbose, tests_dir=tests_dir)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
check_dependencies()
|
check_dependencies()
|
||||||
main()
|
main()
|
||||||
|
48
unifytex
Executable file
48
unifytex
Executable file
@ -0,0 +1,48 @@
|
|||||||
|
#!/bin/python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
def dynamic_includes(folder_path):
|
||||||
|
"""Generate separate LaTeX files recursively"""
|
||||||
|
consolidated_dir = os.path.join(os.getcwd(), "consolidated")
|
||||||
|
os.makedirs(consolidated_dir, exist_ok=True)
|
||||||
|
|
||||||
|
for root, dirs, files in os.walk(folder_path):
|
||||||
|
if not files or os.path.abspath(root) == os.path.abspath(consolidated_dir):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if root == folder_path:
|
||||||
|
folder_name = os.path.basename(folder_path) or "root"
|
||||||
|
else:
|
||||||
|
folder_name = os.path.basename(root)
|
||||||
|
|
||||||
|
output_file = os.path.join(consolidated_dir, f"{folder_name}.tex")
|
||||||
|
|
||||||
|
with open(output_file, "w") as f:
|
||||||
|
f.write("% Autogenerated by unifytex (git.confest.im/boyan_k/Coding_Tools/)\n")
|
||||||
|
for file in sorted(files):
|
||||||
|
if file.endswith(".tex"):
|
||||||
|
relative_path = os.path.relpath(
|
||||||
|
os.path.join(root, file),
|
||||||
|
os.path.dirname(os.path.abspath(folder_path))
|
||||||
|
)
|
||||||
|
|
||||||
|
f.write(f"\\input{{{relative_path}}}\n")
|
||||||
|
|
||||||
|
print(f"Generated {output_file}")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Generate separate LaTeX include files for .tex files recursively")
|
||||||
|
parser.add_argument("directory", help="The directory to process.")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
directory = args.directory
|
||||||
|
|
||||||
|
if not os.path.isdir(directory):
|
||||||
|
raise FileNotFoundError(f"Error: The directory '{directory}' does not exist.")
|
||||||
|
|
||||||
|
dynamic_includes(directory)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Reference in New Issue
Block a user