mirror of
https://github.com/github/gitignore.git
synced 2026-10-30 22:52:32 +01:00
Compare commits
126
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7016e326e4 | ||
|
|
32652622a4 | ||
|
|
8f80fc38c9 | ||
|
|
57286c3887 | ||
|
|
90db345f0d | ||
|
|
dcc0fc7bc2 | ||
|
|
3780fff86c | ||
|
|
4cfd0b81b3 | ||
|
|
afdec22fa1 | ||
|
|
46742213f6 | ||
|
|
7d476866ad | ||
|
|
ca6c873762 | ||
|
|
7338c62e90 | ||
|
|
3407009677 | ||
|
|
8224d3117f | ||
|
|
e5414fa4fe | ||
|
|
cff16449a5 | ||
|
|
8f2f1edc2c | ||
|
|
314d381f1e | ||
|
|
6a98aacd54 | ||
|
|
9275edaddf | ||
|
|
1046d8fba6 | ||
|
|
b632b12ac9 | ||
|
|
5763345204 | ||
|
|
a5221917b7 | ||
|
|
68275fc7aa | ||
|
|
6abe9c03f6 | ||
|
|
42f7c40623 | ||
|
|
618ab22d7c | ||
|
|
1db6a7cf87 | ||
|
|
c62fbb7967 | ||
|
|
9a2ae1c470 | ||
|
|
322d56fec4 | ||
|
|
ccf8d89c54 | ||
|
|
14d5eadc15 | ||
|
|
b0202f339f | ||
|
|
166ce88ec5 | ||
|
|
a4a12a4fa3 | ||
|
|
622da0d813 | ||
|
|
bef6d439ce | ||
|
|
1af287ee8a | ||
|
|
90ef4aada1 | ||
|
|
248de8ed97 | ||
|
|
24b539acec | ||
|
|
25713eb3a5 | ||
|
|
5f5a92fcfe | ||
|
|
47eaa84be9 | ||
|
|
4a96a23dfd | ||
|
|
071d8034a4 | ||
|
|
b42312254f | ||
|
|
4d89c5d3e2 | ||
|
|
aef8819a8f | ||
|
|
8f5497c4be | ||
|
|
70da24ee68 | ||
|
|
4def375658 | ||
|
|
1a7b75fb11 | ||
|
|
81a7cc6c11 | ||
|
|
734bf73afa | ||
|
|
f86606d285 | ||
|
|
61268c1e43 | ||
|
|
d958809c97 | ||
|
|
9947276662 | ||
|
|
23d3287511 | ||
|
|
570fce64e4 | ||
|
|
1187b2cb9b | ||
|
|
e094da038b | ||
|
|
9d7511bedc | ||
|
|
d4753897ec | ||
|
|
a76c0e6d8e | ||
|
|
d0c2ec65c2 | ||
|
|
7247090aa6 | ||
|
|
5b24c9042d | ||
|
|
7441291fc8 | ||
|
|
411ca2450b | ||
|
|
6502030068 | ||
|
|
bf4440e850 | ||
|
|
d36057a9f8 | ||
|
|
3b288cfb37 | ||
|
|
3304408968 | ||
|
|
e81fea5f71 | ||
|
|
c97a73771f | ||
|
|
7db9624f69 | ||
|
|
6836b38f62 | ||
|
|
a850db9d75 | ||
|
|
f6eef37aba | ||
|
|
2a4ac93e79 | ||
|
|
399559e0b7 | ||
|
|
98608a890a | ||
|
|
315e8cbbbd | ||
|
|
844333a10b | ||
|
|
e0041f1269 | ||
|
|
40c5d3211c | ||
|
|
d8635c69ba | ||
|
|
e64eacaa89 | ||
|
|
0befa5a8fd | ||
|
|
51c9bed9d0 | ||
|
|
b7562cc78e | ||
|
|
33ce59b598 | ||
|
|
cd33ea10e8 | ||
|
|
b5bf7e40ff | ||
|
|
cf8b54d020 | ||
|
|
add7cbcaad | ||
|
|
3392aa92c2 | ||
|
|
273b70134f | ||
|
|
6b7a933304 | ||
|
|
ebc4db855a | ||
|
|
0a25801fa9 | ||
|
|
c3b96313ed | ||
|
|
a45008d646 | ||
|
|
edd04dce90 | ||
|
|
52c2f9a7c5 | ||
|
|
1141dbc87f | ||
|
|
08a7300667 | ||
|
|
51d9679541 | ||
|
|
9e92df704e | ||
|
|
647cae16e7 | ||
|
|
b27567d5be | ||
|
|
7b33adcda3 | ||
|
|
1b3fb86582 | ||
|
|
e18a850340 | ||
|
|
21fc4d99eb | ||
|
|
b6629caa12 | ||
|
|
d67fc993d6 | ||
|
|
63caeed028 | ||
|
|
14fea44fd5 | ||
|
|
be40b2ed2c |
No files matched your search
@@ -1,3 +1,10 @@
|
||||
### Link to the application or project's homepage
|
||||
|
||||
_TODO_
|
||||
<!---
|
||||
Link to the project or application's homepage.
|
||||
--->
|
||||
|
||||
### Reasons for making this change
|
||||
|
||||
_TODO_
|
||||
@@ -8,16 +15,18 @@ Please provide some background for this change.
|
||||
### Links to documentation supporting these rule changes
|
||||
|
||||
_TODO_
|
||||
|
||||
<!---
|
||||
Link to the project docs, any existing .gitignore files that project may have in it's own repo, etc
|
||||
Link to the project docs, any existing .gitignore files that project may have in its own repo, etc
|
||||
--->
|
||||
|
||||
### If this is a new template
|
||||
|
||||
Link to application or project’s homepage: TODO
|
||||
|
||||
### Merge and Approval Steps
|
||||
- [ ] Confirm that you've read the [contribution guidelines](https://github.com/github/gitignore/tree/main?tab=readme-ov-file#contributing-guidelines) and ensured your PR aligns
|
||||
- [ ] Ensure CI is passing
|
||||
- [ ] Get a review and Approval from one of the maintainers
|
||||
|
||||
<!---
|
||||
Please ensure you accomplish these tasks in order to get your contribution accepted
|
||||
--->
|
||||
- [ ] I have read the [contribution guidelines](https://github.com/github/gitignore/tree/main?tab=readme-ov-file#contributing-guidelines) and understand my PR will be closed if it doesn't meet these guidelines
|
||||
|
||||
<!---
|
||||
Once done, please wait for a GitHub maintainer to review your PR and if necessary,
|
||||
work with them to address any findings.
|
||||
--->
|
||||
+2
-1
@@ -16,7 +16,8 @@
|
||||
rad.json
|
||||
#Translation Base-file
|
||||
*.g.xlf
|
||||
#License-file
|
||||
#License-files
|
||||
*.bclicense
|
||||
*.flf
|
||||
#Test results file
|
||||
TestResults.xml
|
||||
@@ -23,7 +23,6 @@
|
||||
*.dll
|
||||
*.so.*
|
||||
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
+21
-11
@@ -2,36 +2,46 @@
|
||||
|
||||
We’d love you to help us improve this project. To help us keep this collection
|
||||
high quality, we request that contributions adhere to the following guidelines.
|
||||
Any contributions that don't meet these guidelines will be closed.
|
||||
|
||||
- **Provide a link to the application or project’s homepage**. Unless it’s
|
||||
extremely popular, there’s a chance the maintainers don’t know about or use
|
||||
the language, framework, editor, app, or project your change applies to.
|
||||
|
||||
- **Provide a reason for making this change**. Even if it seems self-evident,
|
||||
please take a sentence or two to tell us why your change or addition should
|
||||
happen. It’s especially helpful to articulate why this change applies to
|
||||
*everyone* who works with the applicable technology, rather than just you or
|
||||
your team.
|
||||
|
||||
- **Provide links to documentation** supporting the change you’re making.
|
||||
Current, canonical documentation mentioning the files being ignored is best.
|
||||
If documentation isn’t available to support your change, do the best you can
|
||||
to explain what the files being ignored are for.
|
||||
|
||||
- **Explain why you’re making a change**. Even if it seems self-evident, please
|
||||
take a sentence or two to tell us why your change or addition should happen.
|
||||
It’s especially helpful to articulate why this change applies to *everyone*
|
||||
who works with the applicable technology, rather than just you or your team.
|
||||
- **Keep scope as limited as possible**. Changes should be as small as possible
|
||||
and apply to the most specific gitignore template available for the target
|
||||
application. For example: OS-specific ignore rules like `.DS_Store` are not
|
||||
accepted anywhere but their specific gitignore, `Global/macOS.gitignore` in
|
||||
this case.
|
||||
|
||||
- **Please consider the scope of your change**. If your change specific to a
|
||||
certain language or framework, then make sure the change is made to the
|
||||
template for that language or framework, rather than to the template for an
|
||||
editor, tool, or operating system.
|
||||
|
||||
- **Please only modify *one template* per pull request**. This helps keep pull
|
||||
- **Only modify *one template* per pull request**. This helps keep pull
|
||||
requests and feedback focused on a specific project or technology.
|
||||
|
||||
- **Add new rules to the most appropriate existing section**. Please ensure
|
||||
your contribution does not create duplicate sections or add rules in
|
||||
unrelated sections.
|
||||
|
||||
- **No duplicate rules**. It's easy to do, but it creates confusion and
|
||||
introduces the risk of one or the other being missed in an update.
|
||||
|
||||
In general, the more you can do to help us understand the change you’re making,
|
||||
the more likely we’ll be to accept your contribution quickly.
|
||||
|
||||
If a template is mostly a list of files installed by a particular version of
|
||||
some software (e.g. a PHP framework) then it's brittle and probably no more
|
||||
helpful than a simple `ls`. If it's not possible to curate a small set of
|
||||
useful rules, then the template might not be a good fit for this collection.
|
||||
useful rules, then the template is not a good fit for this collection.
|
||||
|
||||
Please also understand that we can’t list every tool that ever existed.
|
||||
Our aim is to curate a collection of the *most common and helpful* templates,
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# Deno
|
||||
# https://deno.com/
|
||||
|
||||
# Cache directory (when using project-local DENO_DIR)
|
||||
# https://docs.deno.com/runtime/fundamentals/setup/#deno_dir
|
||||
.deno/
|
||||
|
||||
# Coverage reports
|
||||
# https://docs.deno.com/runtime/reference/cli/coverage/
|
||||
coverage/
|
||||
*.lcov
|
||||
@@ -0,0 +1,68 @@
|
||||
# AI agents and assistants
|
||||
#
|
||||
# Some common agent instruction and project configuration files are listed
|
||||
# below as commented-out examples. They are often intentionally committed and
|
||||
# shared with a team, so only uncomment them if they are local-only in your
|
||||
# project.
|
||||
|
||||
# GEMINI.md
|
||||
# WARP.md
|
||||
# CRUSH.md
|
||||
# QWEN.md
|
||||
|
||||
# OpenAI Codex
|
||||
# AGENTS.md
|
||||
# .codex/
|
||||
|
||||
# Aider
|
||||
.aider.input.history
|
||||
.aider.chat.history.md
|
||||
.aider.llm.history
|
||||
.aider.tags.cache.v*
|
||||
# .aiderignore
|
||||
|
||||
# Claude Code
|
||||
.claude/*.local.json
|
||||
.claude/**/*.log
|
||||
CLAUDE.local.md
|
||||
# .claude/
|
||||
|
||||
# Gemini CLI
|
||||
gemini-debug.log
|
||||
.gemini-clipboard/
|
||||
# .gemini/
|
||||
|
||||
# Cursor AI
|
||||
# .cursorrules
|
||||
# .cursor/
|
||||
# .cursor.json
|
||||
# .cursor-settings.yaml
|
||||
|
||||
# Continue
|
||||
# .continue/
|
||||
# .continuerc.json
|
||||
|
||||
# Cline
|
||||
# .cline/
|
||||
# .clinerules
|
||||
# cline.json
|
||||
|
||||
# Other agent/editor project config
|
||||
# .warp/
|
||||
# .crush/
|
||||
# .codeium/
|
||||
# .deepseek/
|
||||
# .amazon-codewhisperer/
|
||||
# .tabnineignore
|
||||
# .tabnine/
|
||||
|
||||
# GitHub Copilot
|
||||
# .github/copilot-instructions.md
|
||||
|
||||
# Windsurf Editor
|
||||
# .windsurfrules
|
||||
# .windsurf/
|
||||
|
||||
# Replit AI Development
|
||||
# .replit
|
||||
# replit.nix
|
||||
@@ -1,2 +1,5 @@
|
||||
*.retry
|
||||
# The default root path for Ansible config files on the controller
|
||||
.ansible/
|
||||
|
||||
# Retry files generated for failed Ansible playbook runs
|
||||
*.retry
|
||||
@@ -1,5 +1,17 @@
|
||||
# Generic backup files
|
||||
*.bak
|
||||
*.back
|
||||
*.backup
|
||||
|
||||
# Norton Ghost backup files
|
||||
*.gho
|
||||
|
||||
# Generic original files
|
||||
*.ori
|
||||
*.orig
|
||||
*.original
|
||||
|
||||
# Generic temporary files
|
||||
*.tmp
|
||||
*.temp
|
||||
*.temporary
|
||||
@@ -63,7 +63,8 @@ atlassian-ide-plugin.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
.idea/sonarlint.xml # see https://community.sonarsource.com/t/is-the-file-idea-idea-idea-sonarlint-xml-intended-to-be-under-source-control/121119
|
||||
# see https://community.sonarsource.com/t/is-the-file-idea-idea-idea-sonarlint-xml-intended-to-be-under-source-control/121119
|
||||
.idea/sonarlint.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*.autosave
|
||||
*.slx.r*
|
||||
*.mdl.r*
|
||||
*.bak
|
||||
|
||||
# Derived content-obscured files
|
||||
*.p
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
.sisyphus/*
|
||||
!.sisyphus/rules/
|
||||
@@ -1,5 +1,16 @@
|
||||
# Virtualenv
|
||||
# https://realpython.com/python-virtual-environments-a-primer/#the-virtualenv-project
|
||||
.venv/
|
||||
venv/
|
||||
.python-version
|
||||
|
||||
# pyenv: Simple Python Version Management
|
||||
pyvenv.cfg
|
||||
|
||||
# pip: package installer for Python
|
||||
pip-selfcheck.json
|
||||
|
||||
# Custom python interpreter
|
||||
.Python
|
||||
[Bb]in
|
||||
[Ii]nclude
|
||||
@@ -7,6 +18,3 @@
|
||||
[Ll]ib64
|
||||
[Ll]ocal
|
||||
[Ss]cripts
|
||||
pyvenv.cfg
|
||||
.venv
|
||||
pip-selfcheck.json
|
||||
@@ -1,3 +1,4 @@
|
||||
# Visual Studio Code
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Zed
|
||||
# https://zed.dev/docs/configuring-zed#settings-files
|
||||
#
|
||||
# Zed stores project settings in a .zed/ directory, similar to .vscode/.
|
||||
# By default, ignore the directory but allow commonly shared config files.
|
||||
|
||||
.zed/*
|
||||
!.zed/settings.json
|
||||
!.zed/tasks.json
|
||||
!.zed/debug.json
|
||||
+33
-2
@@ -6,10 +6,10 @@ __MACOSX/
|
||||
.LSOverride
|
||||
Icon[␍]
|
||||
|
||||
# Thumbnails
|
||||
# Resource forks
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
# Files and directories that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
@@ -17,6 +17,15 @@ Icon[
]
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
.com.apple.timemachine.supported
|
||||
.PKInstallSandboxManager
|
||||
.PKInstallSandboxManager-SystemSoftware
|
||||
.hotfiles.btree
|
||||
.vol
|
||||
.file
|
||||
.disk_label*
|
||||
lost+found
|
||||
.HFS+ Private Directory Data[␍]
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
@@ -24,3 +33,25 @@ Icon[
]
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
# Mac OS 6 to 9
|
||||
Desktop DB
|
||||
Desktop DF
|
||||
TheFindByContentFolder
|
||||
TheVolumeSettingsFolder
|
||||
.FBCIndex
|
||||
.FBCSemaphoreFile
|
||||
.FBCLockFolder
|
||||
|
||||
# Quota system
|
||||
.quota.group
|
||||
.quota.user
|
||||
.quota.ops.group
|
||||
.quota.ops.user
|
||||
|
||||
# TimeMachine
|
||||
Backups.backupdb
|
||||
.MobileBackups
|
||||
.MobileBackups.trash
|
||||
MobileBackups.trash
|
||||
tmbootpicker.efi
|
||||
@@ -1,3 +1,6 @@
|
||||
# Godot 4.2+ specific ignores
|
||||
~*.dll
|
||||
|
||||
# Godot 4+ specific ignores
|
||||
.godot/
|
||||
.nomedia
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ gradle-app.setting
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
||||
|
||||
# Avoid ignore Gradle wrappper properties
|
||||
# Avoid ignore Gradle wrapper properties
|
||||
!gradle-wrapper.properties
|
||||
|
||||
# Cache of project
|
||||
|
||||
+70
-35
@@ -5,46 +5,81 @@
|
||||
# Official AMD ROCm HIP .gitignore: https://github.com/ROCm/hip/blob/amd-staging/.gitignore
|
||||
|
||||
# 1. Build directories and files
|
||||
/build/ # common build directory
|
||||
/CMakeFiles/ # CMake internal files
|
||||
/CMakeCache.txt # CMake cache file
|
||||
/Makefile # autogenerated Makefile
|
||||
/cmake_install.cmake # install script
|
||||
/install_manifest.txt # install manifest list
|
||||
*.ninja-dep # Ninja dependency files
|
||||
*.ninja_log # Ninja log files
|
||||
meson-logs/ # Meson log directory
|
||||
# common build directory
|
||||
/build/
|
||||
# CMake internal files
|
||||
/CMakeFiles/
|
||||
# CMake cache file
|
||||
/CMakeCache.txt
|
||||
# autogenerated Makefile
|
||||
/Makefile
|
||||
# install script
|
||||
/cmake_install.cmake
|
||||
# install manifest list
|
||||
/install_manifest.txt
|
||||
# Ninja dependency files
|
||||
*.ninja-dep
|
||||
# Ninja log files
|
||||
*.ninja_log
|
||||
# Meson log directory
|
||||
meson-logs/
|
||||
|
||||
# 2. Compilation outputs and intermediates
|
||||
*.o # object files
|
||||
*.obj # Windows object files
|
||||
*.so # shared libraries
|
||||
*.a # static librarie
|
||||
*.d # dependency files
|
||||
*.gch # precompiled headers
|
||||
*.ii # preprocessed output
|
||||
*.ii.cpp # C++ preprocessed output
|
||||
*.out # generic executable outputs
|
||||
*.exe # Windows executables
|
||||
# object files
|
||||
*.o
|
||||
# Windows object files
|
||||
*.obj
|
||||
# shared libraries
|
||||
*.so
|
||||
# static librarie
|
||||
*.a
|
||||
# dependency files
|
||||
*.d
|
||||
# precompiled headers
|
||||
*.gch
|
||||
# preprocessed output
|
||||
*.ii
|
||||
# C++ preprocessed output
|
||||
*.ii.cpp
|
||||
# generic executable outputs
|
||||
*.out
|
||||
# Windows executables
|
||||
*.exe
|
||||
|
||||
# 3. HIP/ROCm specific binaries and intermediates
|
||||
*.hsaco # ROCm compiled binary
|
||||
*.s # assembly output
|
||||
*.kernels.cpp # autogenerated kernel sources
|
||||
*.hip.cpp.* # hipcc intermediate outputs
|
||||
# ROCm compiled binary
|
||||
*.hsaco
|
||||
# assembly output
|
||||
*.s
|
||||
# autogenerated kernel sources
|
||||
*.kernels.cpp
|
||||
# hipcc intermediate outputs
|
||||
*.hip.cpp.*
|
||||
|
||||
# 4. Official sample binaries and tutorial outputs
|
||||
bin/hipInfo # sample binary
|
||||
bin/hipBusBandwidth # sample binary
|
||||
bin/hipDispatchLatency # sample binary
|
||||
bin/hipify-clang # sample tool
|
||||
samples/**/*.out # tutorial outputs
|
||||
samples/**/*.code # ISA/code dumps
|
||||
samples/**/*.hsaco # compiled binaries
|
||||
samples/**/*.co # kernel code outputs
|
||||
# sample binary
|
||||
bin/hipInfo
|
||||
# sample binary
|
||||
bin/hipBusBandwidth
|
||||
# sample binary
|
||||
bin/hipDispatchLatency
|
||||
# sample tool
|
||||
bin/hipify-clang
|
||||
# tutorial outputs
|
||||
samples/**/*.out
|
||||
# ISA/code dumps
|
||||
samples/**/*.code
|
||||
# compiled binaries
|
||||
samples/**/*.hsaco
|
||||
# kernel code outputs
|
||||
samples/**/*.co
|
||||
|
||||
# 5. Tags, logs and test outputs
|
||||
tags # ctags index
|
||||
*.log # log files
|
||||
/tests_output/ # custom test output directory
|
||||
/samples_output/ # custom sample output directory
|
||||
# ctags index
|
||||
tags
|
||||
# log files
|
||||
*.log
|
||||
# custom test output directory
|
||||
/tests_output/
|
||||
# custom sample output directory
|
||||
/samples_output/
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
# Files generated by invoking Julia with --track-allocation
|
||||
*.jl.mem
|
||||
*.jl.*.mem
|
||||
|
||||
# System-specific files and directories generated by the BinaryProvider and BinDeps packages
|
||||
# They contain absolute paths specific to the host computer, and so should not be committed
|
||||
@@ -26,3 +27,6 @@ Manifest*.toml
|
||||
# File generated by the Preferences package to store local preferences
|
||||
LocalPreferences.toml
|
||||
JuliaLocalPreferences.toml
|
||||
|
||||
# Conda environment and metadata created in the project directory by the CondaPkg package
|
||||
.CondaPkg/
|
||||
@@ -36,5 +36,8 @@ fp-info-cache
|
||||
# Archived Backups (KiCad 6.0)
|
||||
**/*-backups/*.zip
|
||||
|
||||
# Local git-based history (KiCad 9.0+)
|
||||
.history
|
||||
|
||||
# Local project settings
|
||||
*.kicad_prl
|
||||
@@ -21,6 +21,7 @@ Homestead.yaml
|
||||
Homestead.json
|
||||
/.vagrant
|
||||
.phpunit.result.cache
|
||||
/.phpunit.cache
|
||||
|
||||
/public/build
|
||||
/storage/pail
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
## LASAL ###
|
||||
# website: https://www.sigmatek-automation.com/en/products/engineering-tool-lasal/
|
||||
|
||||
# lasal screen/visu runtime folders generated during build
|
||||
**/Runtime
|
||||
**/BAK
|
||||
**/Language
|
||||
**/TempPreview
|
||||
|
||||
# lasal class runtime folders generated during build
|
||||
ProjectInternal
|
||||
Internal
|
||||
**/Network/*/*.st
|
||||
**/Drive/*.st
|
||||
|
||||
# bootdisk files
|
||||
**/Bootdisk
|
||||
|
||||
# various filetypes generated at runtime or used for internal backups
|
||||
*.ldi
|
||||
*.bak
|
||||
*.lob
|
||||
*.lba
|
||||
*.lcb
|
||||
*.lock
|
||||
*.plc
|
||||
*.7z
|
||||
*.zip
|
||||
*.lcc
|
||||
*.lds
|
||||
|
||||
# tag files generated by the compiler
|
||||
*.mme
|
||||
**/MaeExp.txt
|
||||
**/MaeExp.xml
|
||||
|
||||
# SigCLib requires lba and lob files
|
||||
!cObjLib.lob
|
||||
!cObjLib.lba
|
||||
|
||||
# opc related classes added automatically from lasal instance
|
||||
!**/Class/OPC_UA/**
|
||||
!**/Class/OPC_UA_Client/**
|
||||
!**/Class/OPC_UA_Server/**
|
||||
!**/Class/OPC_UA_ModuleBase/**
|
||||
!**/Class/OPC_UA_AddressSpace/**
|
||||
!**/Class/OPC_UA_OpenSSL_v1_1_1/**
|
||||
@@ -0,0 +1,53 @@
|
||||
# Build System Artifacts
|
||||
|
||||
# MoonBit default build output directory.
|
||||
_build/
|
||||
# Local MoonBit package cache directory.
|
||||
.mooncakes/
|
||||
|
||||
# Coverage and Test Artifacts
|
||||
|
||||
# Coverage reports generated by MoonBit tooling.
|
||||
moonbit-coverage-*.txt
|
||||
# Coverage output directory used by coverage commands.
|
||||
_coverage/
|
||||
# Bisect runtime coverage data file.
|
||||
bisect.coverage
|
||||
|
||||
# JavaScript Target Artifacts
|
||||
|
||||
# Uncomment if generated JavaScript should be ignored.
|
||||
# *.js
|
||||
# Source map files generated for JavaScript output.
|
||||
*.js.map
|
||||
# Node.js dependencies used in JS target workflows.
|
||||
node_modules/
|
||||
|
||||
# WebAssembly Target Artifacts
|
||||
|
||||
# Compiled WebAssembly binaries.
|
||||
*.wasm
|
||||
# WebAssembly text format output.
|
||||
*.wat
|
||||
|
||||
# MoonBit Pilot / Agent Artifacts
|
||||
|
||||
# MoonBit agent runtime state and temporary files.
|
||||
.moonagent/
|
||||
|
||||
# LLVM Backend Artifacts
|
||||
|
||||
# LLVM textual intermediate representation (IR) files.
|
||||
*.ll
|
||||
# LLVM bitcode files.
|
||||
*.bc
|
||||
# Native object files from LLVM/native compilation.
|
||||
*.o
|
||||
# Generated assembly source files.
|
||||
*.s
|
||||
# Default executable output name on Unix-like systems.
|
||||
*.out
|
||||
# Native executable output on Windows.
|
||||
*.exe
|
||||
# macOS debug symbol bundles.
|
||||
*.dSYM/
|
||||
+1
-2
@@ -92,9 +92,8 @@ dist
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
# vuepress v2.x temp directory
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Sveltekit cache directory
|
||||
.svelte-kit/
|
||||
|
||||
+6
-2
@@ -47,6 +47,7 @@ nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py.cover
|
||||
*.lcov
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
@@ -122,13 +123,14 @@ ipython_config.py
|
||||
# pixi.lock
|
||||
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
||||
# in the .venv directory. It is recommended not to include this directory in version control.
|
||||
.pixi
|
||||
.pixi/*
|
||||
!.pixi/config.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat-schedule*
|
||||
celerybeat.pid
|
||||
|
||||
# Redis
|
||||
@@ -200,6 +202,8 @@ cython_debug/
|
||||
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
||||
# you could uncomment the following to ignore the entire vscode folder
|
||||
# .vscode/
|
||||
# Temporary file for partial code execution
|
||||
tempCodeRunnerFile.py
|
||||
|
||||
# Ruff stuff:
|
||||
.ruff_cache/
|
||||
|
||||
@@ -29,8 +29,10 @@ ui_*.h
|
||||
*.jsc
|
||||
Makefile*
|
||||
*build-*
|
||||
build/
|
||||
*.qm
|
||||
*.prl
|
||||
*.qmlls.ini
|
||||
|
||||
# Qt unit tests
|
||||
target_wrapper.*
|
||||
|
||||
@@ -30,12 +30,15 @@ We support a collection of templates, organized in this way:
|
||||
or merge these rules into your project-specific templates if you want to use
|
||||
them permanently.
|
||||
- [`community`](./community) contains specialized templates for other popular
|
||||
languages, tools and project, which don't currently belong in the mainstream
|
||||
languages, tools, and projects that don't currently belong in the mainstream
|
||||
templates. These should be added to your project-specific templates when you
|
||||
decide to adopt the framework or tool.
|
||||
|
||||
## What makes a good template?
|
||||
|
||||
First and foremost, a template contribution must adhere to our
|
||||
[Contributing Guidelines](CONTRIBUTING.md).
|
||||
|
||||
A template should contain a set of rules to help Git repositories work with a
|
||||
specific programming language, framework, tool or environment.
|
||||
|
||||
@@ -50,7 +53,7 @@ If you have a small set of rules, or want to support a technology that is not
|
||||
widely in use, and still believe this will be helpful to others, please read the
|
||||
section about [specialized templates](#specialized-templates) for more details.
|
||||
|
||||
Include details when opening pull request if the template is important and visible. We
|
||||
Include details when opening a pull request if the template is important and visible. We
|
||||
may not accept it immediately, but we can promote it to the root at a later date
|
||||
based on interest.
|
||||
|
||||
@@ -61,33 +64,7 @@ include your language, tool, or project, it’s not because it’s not awesome.
|
||||
|
||||
## Contributing guidelines
|
||||
|
||||
We’d love for you to help us improve this project. To help us keep this collection
|
||||
high quality, we request that contributions adhere to the following guidelines.
|
||||
|
||||
- **Provide a link to the application or project’s homepage**. Unless it’s
|
||||
extremely popular, there’s a chance the maintainers don’t know about or use
|
||||
the language, framework, editor, app, or project your change applies to.
|
||||
|
||||
- **Provide links to documentation** supporting the change you’re making.
|
||||
Current, canonical documentation mentioning the files being ignored is best.
|
||||
If documentation isn’t available to support your change, do the best you can
|
||||
to explain what the files being ignored are for.
|
||||
|
||||
- **Explain why you’re making a change**. Even if it seems self-evident, please
|
||||
take a sentence or two to tell us why your change or addition should happen.
|
||||
It’s especially helpful to articulate why this change applies to _everyone_
|
||||
who works with the applicable technology, rather than just you or your team.
|
||||
|
||||
- **Please consider the scope of your change**. If your change is specific to a
|
||||
certain language or framework, then make sure the change is made to the
|
||||
template for that language or framework, rather than to the template for an
|
||||
editor, tool, or operating system.
|
||||
|
||||
- **Please only modify _one template_ per pull request**. This helps keep pull
|
||||
requests and feedback focused on a specific project or technology.
|
||||
|
||||
In general, the more you can do to help us understand the change you’re making,
|
||||
the more likely we’ll be to accept your contribution quickly.
|
||||
Please see our [Contributing Guidelines](CONTRIBUTING.md).
|
||||
|
||||
## Versioned templates
|
||||
|
||||
@@ -153,3 +130,4 @@ by automatically forking the project and prompting to send a pull request too.
|
||||
## License
|
||||
|
||||
[CC0-1.0](./LICENSE).
|
||||
|
||||
@@ -13,6 +13,9 @@ target
|
||||
# Contains mutation testing data
|
||||
**/mutants.out*/
|
||||
|
||||
# rustc will dump stack traces when hitting an internal compiler error to PWD
|
||||
rustc-ice-*.txt
|
||||
|
||||
# RustRover
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
*.class
|
||||
*.tasty
|
||||
*.log
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# gitignore file for a SolidWorks project
|
||||
|
||||
# SolidWorks temporary files
|
||||
~$*.sldprt
|
||||
~$*.sldasm
|
||||
~$*.slddrw
|
||||
~$*.sld
|
||||
|
||||
# For systems with case-sensitive (SolidWorks uses both)
|
||||
~$*.SLDPRT
|
||||
~$*.SLDASM
|
||||
~$*.SLDDRW
|
||||
~$*.SLD
|
||||
|
||||
# SolidWorks backups and auto-recovery
|
||||
*.bak
|
||||
*.swbak
|
||||
|
||||
# Cache of simulation results
|
||||
/simulation_results/
|
||||
@@ -55,3 +55,6 @@ LineIDs.dbg.bak
|
||||
*.~u
|
||||
*.project.~u
|
||||
*.suo
|
||||
|
||||
# TwinCAT Measurement
|
||||
*.vsm
|
||||
@@ -2,6 +2,9 @@
|
||||
#
|
||||
# Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore
|
||||
#
|
||||
# Recommended: add any editor/OS/tool-specific ignore rules from the Global/ templates as needed.
|
||||
# See: https://github.com/github/gitignore/tree/main/Global
|
||||
#
|
||||
.utmp/
|
||||
/[Ll]ibrary/
|
||||
/[Tt]emp/
|
||||
@@ -43,6 +46,7 @@ ExportedObj/
|
||||
*.csproj
|
||||
*.unityproj
|
||||
*.sln
|
||||
*.slnx
|
||||
*.suo
|
||||
*.tmp
|
||||
*.user
|
||||
@@ -97,3 +101,6 @@ InitTestScene*.unity*
|
||||
|
||||
# Auto-generated scenes by play mode tests
|
||||
/[Aa]ssets/[Ii]nit[Tt]est[Ss]cene*.unity*
|
||||
|
||||
# Auto-generated cache in Assets folder
|
||||
/[Aa]ssets/[Ss]ceneDependencyCache*
|
||||
@@ -86,6 +86,7 @@ BenchmarkDotNet.Artifacts/
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
.artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
# Wordpress - ignore core, configuration, examples, uploads and logs.
|
||||
# WordPress - ignore core, configuration, examples, uploads and logs.
|
||||
# https://github.com/github/gitignore/blob/main/WordPress.gitignore
|
||||
|
||||
# Core
|
||||
@@ -45,4 +45,4 @@ wp-config.php
|
||||
#
|
||||
# Note: If you wish to whitelist themes,
|
||||
# uncomment the next line
|
||||
#/wp-content/themes
|
||||
#/wp-content/themes
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# database
|
||||
*.sqlite
|
||||
|
||||
# package-json
|
||||
package-json.lock
|
||||
|
||||
# bun deploy file
|
||||
node_modules.bun
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and *not* Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
@@ -0,0 +1,27 @@
|
||||
# Zephyr RTOS build artifacts
|
||||
/build/
|
||||
/twister-out*/
|
||||
|
||||
# Generated configuration files
|
||||
*.config
|
||||
*.config.old
|
||||
/zephyr/.config
|
||||
|
||||
# Device tree generated files
|
||||
*.dts.pre.tmp
|
||||
*.dts_compiled
|
||||
|
||||
# Kconfig generated
|
||||
autoconf.h
|
||||
|
||||
# West workspace
|
||||
/.west/
|
||||
|
||||
# Python virtual environment
|
||||
/.venv/
|
||||
/venv/
|
||||
|
||||
# IDE
|
||||
.vscode/launch.json
|
||||
.vscode/tasks.json
|
||||
*.jlink
|
||||
@@ -0,0 +1,5 @@
|
||||
# FreeCAD backup and temporary files
|
||||
*.FC.lock
|
||||
*.bak
|
||||
*.FCBak
|
||||
*.tmp
|
||||
@@ -0,0 +1,11 @@
|
||||
*Script
|
||||
|
||||
# Holmake generated files
|
||||
*Theory.sig
|
||||
*Theory.sml
|
||||
*.uo
|
||||
*.ui
|
||||
|
||||
# Holmake auxiliary files
|
||||
.hollogs
|
||||
.HOLMK
|
||||
@@ -11,15 +11,22 @@
|
||||
node_modules/
|
||||
|
||||
# Expo local state and caches
|
||||
.expo/ # runtime state (Metro bundler, dev-client data, tunnels)
|
||||
.expo-shared/ # shared project settings (app.json edits, etc.)
|
||||
# runtime state (Metro bundler, dev-client data, tunnels)
|
||||
.expo/
|
||||
# shared project settings (app.json edits, etc.)
|
||||
.expo-shared/
|
||||
|
||||
# Metro bundler caches/logs
|
||||
*.expo # generic Expo temp files
|
||||
*.tunnel # Expo DevTools tunnels
|
||||
*.cache # Metro cache folder
|
||||
*.tmp # temp files created during bundling
|
||||
*.log # build or Metro logs
|
||||
# generic Expo temp files
|
||||
*.expo
|
||||
# Expo DevTools tunnels
|
||||
*.tunnel
|
||||
# Metro cache folder
|
||||
*.cache
|
||||
# temp files created during bundling
|
||||
*.tmp
|
||||
# build or Metro logs
|
||||
*.log
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
|
||||
@@ -4,27 +4,38 @@
|
||||
# Compiled MQL5 executables (binaries)
|
||||
# These are generated from .mq5 source files and should not be committed.
|
||||
*.ex5
|
||||
*.ex4 # For MQL4 compatibility if you also manage MT4 projects in a similar structure
|
||||
# For MQL4 compatibility if you also manage MT4 projects in a similar structure
|
||||
*.ex4
|
||||
|
||||
# Log files
|
||||
# Terminal logs, strategy tester logs, and custom logs from Print() functions.
|
||||
*.log
|
||||
*.slog # Strategy Tester logs
|
||||
# Strategy Tester logs
|
||||
*.slog
|
||||
|
||||
# Strategy Tester specific files
|
||||
# History data, optimization results, and temporary files used by the tester.
|
||||
*.fxt # FXT files (history data for testing)
|
||||
*.hst # History data files (can be large)
|
||||
*.ini # Initialization files (often generated by tester or EAs)
|
||||
*.dat # Data files (various purposes, often temporary)
|
||||
*.csv # CSV export files (e.g., from tester reports)
|
||||
*.jrn # Journal files (tester journal)
|
||||
# FXT files (history data for testing)
|
||||
*.fxt
|
||||
# History data files (can be large)
|
||||
*.hst
|
||||
# Initialization files (often generated by tester or EAs)
|
||||
*.ini
|
||||
# Data files (various purposes, often temporary)
|
||||
*.dat
|
||||
# CSV export files (e.g., from tester reports)
|
||||
*.csv
|
||||
# Journal files (tester journal)
|
||||
*.jrn
|
||||
|
||||
# Market Watch sets and profiles
|
||||
# User-specific lists of symbols in Market Watch, and terminal profiles.
|
||||
*.set # Market Watch symbol sets
|
||||
*.tpl # Chart templates
|
||||
*.chr # Chart settings files (can be generated when saving templates or profiles)
|
||||
# Market Watch symbol sets
|
||||
*.set
|
||||
# Chart templates
|
||||
*.tpl
|
||||
# Chart settings files (can be generated when saving templates or profiles)
|
||||
*.chr
|
||||
|
||||
# External libraries (DLLs)
|
||||
# If you use custom DLLs, you might want to ignore them if they are built separately
|
||||
@@ -33,14 +44,19 @@
|
||||
|
||||
# User-specific configuration and credentials
|
||||
# Files containing sensitive information or local user settings.
|
||||
.env # Environment variables (e.g., for Python integration credentials)
|
||||
*.cfg # Configuration files (if not meant to be shared)
|
||||
*.json # Be careful: if you have config JSONs you *do* want to commit, add specific exceptions.
|
||||
# Example: !config.json (to include config.json but ignore other *.json)
|
||||
# Environment variables (e.g., for Python integration credentials)
|
||||
.env
|
||||
# Configuration files (if not meant to be shared)
|
||||
*.cfg
|
||||
# Be careful: if you have config JSONs you *do* want to commit, add specific exceptions.
|
||||
*.json
|
||||
# Example: !config.json (to include config.json but ignore other *.json)
|
||||
|
||||
# Temporary files and backup files generated by MetaEditor
|
||||
*.~* # Temporary files (e.g., ~MyScript.mq5)
|
||||
*.bak # Backup files (e.g., MyScript.mq5.bak)
|
||||
# Temporary files (e.g., ~MyScript.mq5)
|
||||
*.~*
|
||||
# Backup files (e.g., MyScript.mq5.bak)
|
||||
*.bak
|
||||
*.mqh.bak
|
||||
*.mq5.bak
|
||||
|
||||
@@ -51,7 +67,11 @@
|
||||
# Python specific ignores (if you also keep Python scripts or Jupyter notebooks in this repository)
|
||||
# These are relevant if your Git repo root is higher up (e.g., the terminal folder itself)
|
||||
# or if you mix Python code within your MQL5 structure.
|
||||
__pycache__/ # Python compiled bytecode cache
|
||||
.ipynb_checkpoints/ # Jupyter Notebook checkpoints
|
||||
*.pyc # Python compiled files
|
||||
*.pyd # Python dynamic modules
|
||||
# Python compiled bytecode cache
|
||||
__pycache__/
|
||||
# Jupyter Notebook checkpoints
|
||||
.ipynb_checkpoints/
|
||||
# Python compiled files
|
||||
*.pyc
|
||||
# Python dynamic modules
|
||||
*.pyd
|
||||
@@ -0,0 +1,12 @@
|
||||
# Tauri
|
||||
# https://tauri.app/
|
||||
#
|
||||
# Recommended: Rust.gitignore
|
||||
|
||||
# Rust compilation output
|
||||
# https://doc.rust-lang.org/cargo/guide/build-cache.html
|
||||
target/
|
||||
|
||||
# WiX Toolset cache (Windows MSI installer builds)
|
||||
# https://v2.tauri.app/distribute/windows-installer/
|
||||
WixTools/
|
||||
@@ -0,0 +1,27 @@
|
||||
#=============================================================================
|
||||
# Microchip MPLAB X IDE .gitignore file.
|
||||
#
|
||||
# MPLABX: https://www.microchip.com/en-us/tools-resources/develop/mplab-x-ide
|
||||
#
|
||||
# MPLABX Version Control:-
|
||||
# https://developerhelp.microchip.com/xwiki/bin/view/software-tools/ides/x/version-control/working-with-version-control/
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# MPLAB X (NetBeans) Project files
|
||||
**/*.X/nbproject/private/
|
||||
**/*.X/nbproject/Makefile-*
|
||||
**/*.X/nbproject/Package-*
|
||||
!**/*.X/nbproject/*.xml
|
||||
|
||||
# MPLAB X Generated Files and Build Output
|
||||
**/*.X/.generated_files/
|
||||
**/*.X/build/
|
||||
**/*.X/dist/
|
||||
**/*.X/debug/
|
||||
|
||||
# MPLAB Code Configurator (MCC)
|
||||
**/*.X/mcc_generated_files/
|
||||
**/*.X/mcc-manifest-*.yml
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Strip trailing whitespace from .gitignore template files.
|
||||
|
||||
This script fixes trailing whitespace issues in gitignore templates,
|
||||
which can cause unexpected behavior in pattern matching.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def strip_file(filepath: str, dry_run: bool = False) -> int:
|
||||
"""Strip trailing whitespace from a file. Returns number of lines fixed."""
|
||||
with open(filepath, "r", encoding="utf-8", errors="replace") as f:
|
||||
lines = f.readlines()
|
||||
|
||||
fixed_count = 0
|
||||
new_lines = []
|
||||
for line in lines:
|
||||
stripped = line.rstrip() + "\n"
|
||||
if stripped != line:
|
||||
fixed_count += 1
|
||||
new_lines.append(stripped)
|
||||
|
||||
# Ensure file ends with a single newline
|
||||
if new_lines and new_lines[-1] == "\n":
|
||||
pass # already ends properly
|
||||
elif not new_lines:
|
||||
new_lines = ["\n"]
|
||||
|
||||
if fixed_count > 0 and not dry_run:
|
||||
with open(filepath, "w", encoding="utf-8", newline="") as f:
|
||||
f.writelines(new_lines)
|
||||
|
||||
return fixed_count
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Strip trailing whitespace from .gitignore templates."
|
||||
)
|
||||
parser.add_argument("files", nargs="*", help="Files to process.")
|
||||
parser.add_argument("--repo-root", default=".", help="Repo root directory.")
|
||||
parser.add_argument(
|
||||
"--dry-run", action="store_true", help="Report but do not modify files."
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.files:
|
||||
targets = args.files
|
||||
else:
|
||||
targets = []
|
||||
for entry in os.listdir(args.repo_root):
|
||||
full = os.path.join(args.repo_root, entry)
|
||||
if os.path.isfile(full) and entry.endswith(".gitignore"):
|
||||
targets.append(full)
|
||||
|
||||
total_fixed = 0
|
||||
for filepath in targets:
|
||||
count = strip_file(filepath, dry_run=args.dry_run)
|
||||
if count > 0:
|
||||
action = "would fix" if args.dry_run else "fixed"
|
||||
print(f" {action} {count} line(s) in {filepath}")
|
||||
total_fixed += count
|
||||
|
||||
if total_fixed == 0:
|
||||
print("No trailing whitespace found.")
|
||||
else:
|
||||
action = "Would fix" if args.dry_run else "Fixed"
|
||||
print(f"\n{action} {total_fixed} line(s) total.")
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,189 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Tests for the gitignore template validator."""
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import pytest
|
||||
|
||||
from validate_templates import (
|
||||
Issue,
|
||||
Severity,
|
||||
ValidationReport,
|
||||
analyze_coverage,
|
||||
check_trailing_whitespace,
|
||||
discover_templates,
|
||||
find_conflicts,
|
||||
find_duplicates,
|
||||
format_report,
|
||||
is_valid_glob_pattern,
|
||||
validate_template,
|
||||
)
|
||||
|
||||
|
||||
class TestIsValidGlobPattern:
|
||||
def test_simple_extension(self):
|
||||
assert is_valid_glob_pattern("*.py") is True
|
||||
|
||||
def test_directory_pattern(self):
|
||||
assert is_valid_glob_pattern("build/") is True
|
||||
|
||||
def test_negation(self):
|
||||
assert is_valid_glob_pattern("!important.txt") is True
|
||||
|
||||
def test_double_star(self):
|
||||
assert is_valid_glob_pattern("**/logs") is True
|
||||
|
||||
def test_bracket_pattern(self):
|
||||
assert is_valid_glob_pattern("*.[oa]") is True
|
||||
|
||||
def test_unmatched_bracket(self):
|
||||
assert is_valid_glob_pattern("*.[o") is False
|
||||
|
||||
def test_empty_after_strip(self):
|
||||
assert is_valid_glob_pattern("!") is False
|
||||
|
||||
def test_rooted_pattern(self):
|
||||
assert is_valid_glob_pattern("/build") is True
|
||||
|
||||
|
||||
class TestCheckTrailingWhitespace:
|
||||
def test_no_trailing(self):
|
||||
assert check_trailing_whitespace("*.py", 1) is None
|
||||
|
||||
def test_with_trailing_space(self):
|
||||
issue = check_trailing_whitespace("*.py ", 5)
|
||||
assert issue is not None
|
||||
assert issue.severity == Severity.WARNING
|
||||
assert issue.line_number == 5
|
||||
|
||||
def test_blank_line_ignored(self):
|
||||
assert check_trailing_whitespace(" ", 1) is None
|
||||
|
||||
|
||||
class TestFindDuplicates:
|
||||
def test_no_duplicates(self):
|
||||
patterns = [(1, "*.py"), (2, "*.js"), (3, "build/")]
|
||||
assert find_duplicates(patterns) == []
|
||||
|
||||
def test_exact_duplicate(self):
|
||||
patterns = [(1, "*.py"), (2, "*.js"), (3, "*.py")]
|
||||
issues = find_duplicates(patterns)
|
||||
assert len(issues) == 1
|
||||
assert issues[0].line_number == 3
|
||||
|
||||
def test_trailing_slash_normalization(self):
|
||||
patterns = [(1, "build"), (2, "build/")]
|
||||
issues = find_duplicates(patterns)
|
||||
assert len(issues) == 1
|
||||
|
||||
|
||||
class TestFindConflicts:
|
||||
def test_no_conflicts(self):
|
||||
patterns = [(1, "*.log"), (2, "*.tmp")]
|
||||
assert find_conflicts(patterns) == []
|
||||
|
||||
def test_include_then_negate(self):
|
||||
patterns = [(1, "*.log"), (2, "!*.log")]
|
||||
issues = find_conflicts(patterns)
|
||||
assert len(issues) == 1
|
||||
assert issues[0].severity == Severity.WARNING
|
||||
|
||||
def test_negate_without_include(self):
|
||||
patterns = [(1, "!important.txt")]
|
||||
issues = find_conflicts(patterns)
|
||||
assert len(issues) == 0
|
||||
|
||||
|
||||
class TestAnalyzeCoverage:
|
||||
def test_many_wildcards(self):
|
||||
patterns = [(i, f"*.ext{i}") for i in range(12)]
|
||||
issues = analyze_coverage(patterns)
|
||||
msgs = [i.message for i in issues]
|
||||
assert any("wildcard" in m for m in msgs)
|
||||
|
||||
def test_no_directory_patterns(self):
|
||||
patterns = [(i, f"*.ext{i}") for i in range(6)]
|
||||
issues = analyze_coverage(patterns)
|
||||
msgs = [i.message for i in issues]
|
||||
assert any("directory" in m.lower() for m in msgs)
|
||||
|
||||
def test_duplicate_extension_suggestion(self):
|
||||
patterns = [(1, "*.py"), (2, "*.py")]
|
||||
issues = analyze_coverage(patterns)
|
||||
msgs = [i.message for i in issues]
|
||||
assert any(".py" in m for m in msgs)
|
||||
|
||||
|
||||
class TestValidateTemplate:
|
||||
def test_valid_template(self):
|
||||
with tempfile.NamedTemporaryFile(
|
||||
mode="w", suffix=".gitignore", delete=False
|
||||
) as f:
|
||||
f.write("# Build output\nbuild/\n*.o\n*.a\n")
|
||||
f.flush()
|
||||
report = validate_template(f.name)
|
||||
os.unlink(f.name)
|
||||
assert report.error_count == 0
|
||||
assert report.pattern_count == 3
|
||||
assert report.comment_count == 1
|
||||
|
||||
def test_invalid_pattern(self):
|
||||
with tempfile.NamedTemporaryFile(
|
||||
mode="w", suffix=".gitignore", delete=False
|
||||
) as f:
|
||||
f.write("*.[invalid\n")
|
||||
f.flush()
|
||||
report = validate_template(f.name)
|
||||
os.unlink(f.name)
|
||||
assert report.error_count > 0
|
||||
|
||||
def test_file_not_found(self):
|
||||
report = validate_template("/nonexistent/file.gitignore")
|
||||
assert report.error_count > 0
|
||||
|
||||
|
||||
class TestFormatReport:
|
||||
def test_clean_report(self):
|
||||
report = ValidationReport(
|
||||
template_file="test.gitignore",
|
||||
total_lines=5,
|
||||
pattern_count=3,
|
||||
comment_count=1,
|
||||
blank_count=1,
|
||||
)
|
||||
output = format_report(report)
|
||||
assert "No issues found" in output
|
||||
|
||||
def test_report_with_issues(self):
|
||||
report = ValidationReport(
|
||||
template_file="test.gitignore",
|
||||
total_lines=5,
|
||||
pattern_count=3,
|
||||
)
|
||||
report.issues.append(
|
||||
Issue(
|
||||
severity=Severity.ERROR,
|
||||
line_number=2,
|
||||
line_content="*.[bad",
|
||||
message="Invalid glob pattern",
|
||||
)
|
||||
)
|
||||
output = format_report(report, verbose=True)
|
||||
assert "ERROR" in output
|
||||
assert "*.[bad" in output
|
||||
|
||||
|
||||
class TestDiscoverTemplates:
|
||||
def test_discover_in_directory(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
# Create fake gitignore files
|
||||
for name in ["Python.gitignore", "Java.gitignore", "README.md"]:
|
||||
with open(os.path.join(tmpdir, name), "w") as f:
|
||||
f.write("# test\n")
|
||||
templates = discover_templates(tmpdir)
|
||||
assert len(templates) == 2
|
||||
assert all(t.endswith(".gitignore") for t in templates)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-v"])
|
||||
@@ -0,0 +1,433 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Gitignore Template Validator
|
||||
|
||||
Validates .gitignore template files for syntax correctness, duplicate patterns,
|
||||
conflicting rules, and provides coverage analysis with detailed reporting.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import fnmatch
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
class Severity(Enum):
|
||||
ERROR = "ERROR"
|
||||
WARNING = "WARNING"
|
||||
SUGGESTION = "SUGGESTION"
|
||||
|
||||
|
||||
@dataclass
|
||||
class Issue:
|
||||
severity: Severity
|
||||
line_number: int
|
||||
line_content: str
|
||||
message: str
|
||||
template_file: str = ""
|
||||
|
||||
|
||||
@dataclass
|
||||
class ValidationReport:
|
||||
template_file: str
|
||||
total_lines: int = 0
|
||||
pattern_count: int = 0
|
||||
comment_count: int = 0
|
||||
blank_count: int = 0
|
||||
issues: List[Issue] = field(default_factory=list)
|
||||
|
||||
@property
|
||||
def error_count(self) -> int:
|
||||
return sum(1 for i in self.issues if i.severity == Severity.ERROR)
|
||||
|
||||
@property
|
||||
def warning_count(self) -> int:
|
||||
return sum(1 for i in self.issues if i.severity == Severity.WARNING)
|
||||
|
||||
@property
|
||||
def suggestion_count(self) -> int:
|
||||
return sum(1 for i in self.issues if i.severity == Severity.SUGGESTION)
|
||||
|
||||
@property
|
||||
def has_errors(self) -> bool:
|
||||
return self.error_count > 0
|
||||
|
||||
|
||||
def is_valid_glob_pattern(pattern: str) -> bool:
|
||||
"""Check if a pattern is a valid glob/gitignore pattern."""
|
||||
clean = pattern.lstrip("!")
|
||||
if clean.startswith("/"):
|
||||
clean = clean[1:]
|
||||
if clean.endswith("/"):
|
||||
clean = clean[:-1]
|
||||
if not clean:
|
||||
return False
|
||||
try:
|
||||
# Check for unmatched brackets
|
||||
bracket_depth = 0
|
||||
i = 0
|
||||
while i < len(clean):
|
||||
ch = clean[i]
|
||||
if ch == "\\" and i + 1 < len(clean):
|
||||
i += 2
|
||||
continue
|
||||
if ch == "[":
|
||||
bracket_depth += 1
|
||||
elif ch == "]":
|
||||
if bracket_depth > 0:
|
||||
bracket_depth -= 1
|
||||
else:
|
||||
return False
|
||||
i += 1
|
||||
if bracket_depth != 0:
|
||||
return False
|
||||
# Test compile the pattern via fnmatch
|
||||
fnmatch.translate(clean)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def check_trailing_whitespace(line: str, line_number: int) -> Optional[Issue]:
|
||||
"""Detect trailing whitespace on a line."""
|
||||
if line != line.rstrip() and line.strip():
|
||||
return Issue(
|
||||
severity=Severity.WARNING,
|
||||
line_number=line_number,
|
||||
line_content=line,
|
||||
message="Line has trailing whitespace",
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
def find_duplicates(patterns: List[tuple]) -> List[Issue]:
|
||||
"""Find duplicate patterns in the list."""
|
||||
issues = []
|
||||
seen = {}
|
||||
for line_num, pattern in patterns:
|
||||
normalized = pattern.strip().rstrip("/")
|
||||
if normalized in seen:
|
||||
issues.append(
|
||||
Issue(
|
||||
severity=Severity.WARNING,
|
||||
line_number=line_num,
|
||||
line_content=pattern,
|
||||
message=f"Duplicate pattern (first seen at line {seen[normalized]})",
|
||||
)
|
||||
)
|
||||
else:
|
||||
seen[normalized] = line_num
|
||||
return issues
|
||||
|
||||
|
||||
def find_conflicts(patterns: List[tuple]) -> List[Issue]:
|
||||
"""Find conflicting include/exclude rules for the same pattern."""
|
||||
issues = []
|
||||
include_patterns = {}
|
||||
exclude_patterns = {}
|
||||
|
||||
for line_num, pattern in patterns:
|
||||
stripped = pattern.strip()
|
||||
if stripped.startswith("!"):
|
||||
base = stripped[1:].strip().rstrip("/")
|
||||
exclude_patterns[base] = line_num
|
||||
if base in include_patterns:
|
||||
issues.append(
|
||||
Issue(
|
||||
severity=Severity.WARNING,
|
||||
line_number=line_num,
|
||||
line_content=stripped,
|
||||
message=(
|
||||
f"Negation pattern conflicts with include at line "
|
||||
f"{include_patterns[base]}. Order matters in gitignore."
|
||||
),
|
||||
)
|
||||
)
|
||||
else:
|
||||
base = stripped.rstrip("/")
|
||||
include_patterns[base] = line_num
|
||||
|
||||
return issues
|
||||
|
||||
|
||||
def analyze_coverage(patterns: List[tuple]) -> List[Issue]:
|
||||
"""Analyze pattern coverage and suggest improvements."""
|
||||
issues = []
|
||||
wildcard_count = 0
|
||||
extension_patterns = []
|
||||
directory_patterns = []
|
||||
|
||||
for line_num, pattern in patterns:
|
||||
stripped = pattern.strip().lstrip("!")
|
||||
if stripped.startswith("*"):
|
||||
wildcard_count += 1
|
||||
if re.match(r"^\*\.[a-zA-Z0-9]+$", stripped):
|
||||
extension_patterns.append((line_num, stripped))
|
||||
if stripped.endswith("/"):
|
||||
directory_patterns.append((line_num, stripped))
|
||||
|
||||
if wildcard_count > 10:
|
||||
issues.append(
|
||||
Issue(
|
||||
severity=Severity.SUGGESTION,
|
||||
line_number=0,
|
||||
line_content="",
|
||||
message=(
|
||||
f"Template has {wildcard_count} wildcard patterns. "
|
||||
"Consider grouping related patterns with comments."
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
ext_groups = {}
|
||||
for line_num, pat in extension_patterns:
|
||||
ext = pat.split(".")[-1].lower()
|
||||
ext_groups.setdefault(ext, []).append(line_num)
|
||||
|
||||
for ext, lines in ext_groups.items():
|
||||
if len(lines) > 1:
|
||||
issues.append(
|
||||
Issue(
|
||||
severity=Severity.SUGGESTION,
|
||||
line_number=lines[1],
|
||||
line_content="",
|
||||
message=(
|
||||
f"Multiple patterns target .{ext} files "
|
||||
f"(lines {', '.join(map(str, lines))}). Consider consolidating."
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
if not directory_patterns and len(patterns) > 5:
|
||||
issues.append(
|
||||
Issue(
|
||||
severity=Severity.SUGGESTION,
|
||||
line_number=0,
|
||||
line_content="",
|
||||
message=(
|
||||
"No directory-specific patterns found. "
|
||||
"Consider adding directory ignores (e.g., build/)."
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
return issues
|
||||
|
||||
|
||||
def validate_template(filepath: str) -> ValidationReport:
|
||||
"""Validate a single gitignore template file."""
|
||||
report = ValidationReport(template_file=filepath)
|
||||
|
||||
try:
|
||||
with open(filepath, "r", encoding="utf-8", errors="replace") as f:
|
||||
lines = f.readlines()
|
||||
except OSError as e:
|
||||
report.issues.append(
|
||||
Issue(
|
||||
severity=Severity.ERROR,
|
||||
line_number=0,
|
||||
line_content="",
|
||||
message=f"Cannot read file: {e}",
|
||||
template_file=filepath,
|
||||
)
|
||||
)
|
||||
return report
|
||||
|
||||
report.total_lines = len(lines)
|
||||
patterns = []
|
||||
|
||||
for i, raw_line in enumerate(lines, start=1):
|
||||
line = raw_line.rstrip("\n\r")
|
||||
|
||||
# Check trailing whitespace
|
||||
ws_issue = check_trailing_whitespace(line, i)
|
||||
if ws_issue:
|
||||
ws_issue.template_file = filepath
|
||||
report.issues.append(ws_issue)
|
||||
|
||||
stripped = line.strip()
|
||||
|
||||
# Blank line
|
||||
if not stripped:
|
||||
report.blank_count += 1
|
||||
continue
|
||||
|
||||
# Comment
|
||||
if stripped.startswith("#"):
|
||||
report.comment_count += 1
|
||||
continue
|
||||
|
||||
# Pattern line
|
||||
report.pattern_count += 1
|
||||
patterns.append((i, stripped))
|
||||
|
||||
# Validate glob syntax
|
||||
if not is_valid_glob_pattern(stripped):
|
||||
report.issues.append(
|
||||
Issue(
|
||||
severity=Severity.ERROR,
|
||||
line_number=i,
|
||||
line_content=stripped,
|
||||
message="Invalid glob pattern syntax",
|
||||
template_file=filepath,
|
||||
)
|
||||
)
|
||||
|
||||
# Check for spaces in patterns (usually a mistake)
|
||||
if " " in stripped and not stripped.startswith("\\"):
|
||||
report.issues.append(
|
||||
Issue(
|
||||
severity=Severity.WARNING,
|
||||
line_number=i,
|
||||
line_content=stripped,
|
||||
message="Pattern contains spaces — this may be unintentional",
|
||||
template_file=filepath,
|
||||
)
|
||||
)
|
||||
|
||||
# Run duplicate detection
|
||||
dup_issues = find_duplicates(patterns)
|
||||
for issue in dup_issues:
|
||||
issue.template_file = filepath
|
||||
report.issues.extend(dup_issues)
|
||||
|
||||
# Run conflict detection
|
||||
conflict_issues = find_conflicts(patterns)
|
||||
for issue in conflict_issues:
|
||||
issue.template_file = filepath
|
||||
report.issues.extend(conflict_issues)
|
||||
|
||||
# Run coverage analysis
|
||||
coverage_issues = analyze_coverage(patterns)
|
||||
for issue in coverage_issues:
|
||||
issue.template_file = filepath
|
||||
report.issues.extend(coverage_issues)
|
||||
|
||||
return report
|
||||
|
||||
|
||||
def format_report(report: ValidationReport, verbose: bool = False) -> str:
|
||||
"""Format a validation report as human-readable text."""
|
||||
lines = []
|
||||
lines.append(f"\n{'='*60}")
|
||||
lines.append(f"File: {report.template_file}")
|
||||
lines.append(f"{'='*60}")
|
||||
lines.append(
|
||||
f" Lines: {report.total_lines} | Patterns: {report.pattern_count} "
|
||||
f"| Comments: {report.comment_count} | Blank: {report.blank_count}"
|
||||
)
|
||||
lines.append(
|
||||
f" Errors: {report.error_count} | Warnings: {report.warning_count} "
|
||||
f"| Suggestions: {report.suggestion_count}"
|
||||
)
|
||||
|
||||
if report.issues:
|
||||
lines.append("")
|
||||
for issue in sorted(report.issues, key=lambda x: (x.severity.value, x.line_number)):
|
||||
prefix = f" [{issue.severity.value}]"
|
||||
loc = f" Line {issue.line_number}:" if issue.line_number > 0 else ""
|
||||
lines.append(f"{prefix}{loc} {issue.message}")
|
||||
if verbose and issue.line_content:
|
||||
lines.append(f" > {issue.line_content}")
|
||||
else:
|
||||
lines.append(" No issues found. ✓")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def discover_templates(repo_root: str) -> List[str]:
|
||||
"""Discover all .gitignore template files in the repository."""
|
||||
templates = []
|
||||
for entry in os.listdir(repo_root):
|
||||
full_path = os.path.join(repo_root, entry)
|
||||
if os.path.isfile(full_path) and entry.endswith(".gitignore"):
|
||||
templates.append(full_path)
|
||||
# Also check Global/ and community/ subdirectories
|
||||
for subdir in ["Global", "community"]:
|
||||
subdir_path = os.path.join(repo_root, subdir)
|
||||
if os.path.isdir(subdir_path):
|
||||
for entry in os.listdir(subdir_path):
|
||||
full_path = os.path.join(subdir_path, entry)
|
||||
if os.path.isfile(full_path) and entry.endswith(".gitignore"):
|
||||
templates.append(full_path)
|
||||
return sorted(templates)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Validate .gitignore template files for common issues."
|
||||
)
|
||||
parser.add_argument(
|
||||
"files",
|
||||
nargs="*",
|
||||
help="Template files to validate. If none given, validates all in repo.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--repo-root",
|
||||
default=".",
|
||||
help="Root directory of the gitignore repo (default: current directory).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--verbose", "-v",
|
||||
action="store_true",
|
||||
help="Show pattern content alongside issues.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--errors-only",
|
||||
action="store_true",
|
||||
help="Only report errors, not warnings or suggestions.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--summary",
|
||||
action="store_true",
|
||||
help="Print only a summary, not per-file details.",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.files:
|
||||
templates = args.files
|
||||
else:
|
||||
templates = discover_templates(args.repo_root)
|
||||
|
||||
if not templates:
|
||||
print("No .gitignore templates found.")
|
||||
sys.exit(0)
|
||||
|
||||
reports = []
|
||||
for tpl in templates:
|
||||
report = validate_template(tpl)
|
||||
reports.append(report)
|
||||
|
||||
total_errors = 0
|
||||
total_warnings = 0
|
||||
total_suggestions = 0
|
||||
|
||||
for report in reports:
|
||||
if args.errors_only:
|
||||
report.issues = [i for i in report.issues if i.severity == Severity.ERROR]
|
||||
if not args.summary:
|
||||
print(format_report(report, verbose=args.verbose))
|
||||
total_errors += report.error_count
|
||||
total_warnings += report.warning_count
|
||||
total_suggestions += report.suggestion_count
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print(f"SUMMARY: {len(reports)} templates validated")
|
||||
print(f" Total errors: {total_errors}")
|
||||
print(f" Total warnings: {total_warnings}")
|
||||
print(f" Total suggestions: {total_suggestions}")
|
||||
print(f"{'='*60}")
|
||||
|
||||
if total_errors > 0:
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user