Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ jobs:
rm -rf branch-test
mkdir branch-test && cd branch-test && git init
git checkout -b master
touch .styleguide
git add .styleguide && git commit -q -m "Initial commit"
touch .wpiformat
git add .wpiformat && git commit -q -m "Initial commit"
wpiformat

# Verify wpiformat reports success if "main" exists
Expand All @@ -117,8 +117,8 @@ jobs:
rm -rf branch-test
mkdir branch-test && cd branch-test && git init
git checkout -b main
touch .styleguide
git add .styleguide && git commit -q -m "Initial commit"
touch .wpiformat
git add .wpiformat && git commit -q -m "Initial commit"
wpiformat

- name: Delete branch-test folder
Expand Down
File renamed without changes.
File renamed without changes.
16 changes: 8 additions & 8 deletions wpiformat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ pip install wpiformat

## Project Setup

To use these tools with a new project, copy `.styleguide`, and `.styleguide-license` from the examples folder into the project and create a new `.clang-format` file based on the desired C/C++ style.
To use these tools with a new project, copy `.wpiformat`, and `.wpiformat-license` from the examples folder into the project and create a new `.clang-format` file based on the desired C/C++ style.

Note: Since wpiformat already handles include ordering, it is recommended to use `SortIncludes: false` in `.clang-format`.

## .styleguide
## .wpiformat

wpiformat checks the current directory for the `.styleguide` file. If one doesn't exist, all parent directories are tried as well. This file contains groups of filename regular expressions.
wpiformat checks the current directory for the `.wpiformat` file. If one doesn't exist, all parent directories are tried as well. This file contains groups of filename regular expressions.
```
groupName {
regex_here
Expand All @@ -36,7 +36,7 @@ The regexes are matched using [re.search()](https://docs.python.org/3/library/re

Empty config groups can be omitted. Directory separators must be "/", not "\\". During processing, they will be replaced internally with an os.sep that is automatically escaped for regexes.

See the `.styleguide` file in the docs/examples directory for all possible groups.
See the `.wpiformat` file in the docs/examples directory for all possible groups.

### Specifying C/C++ files to format

Expand Down Expand Up @@ -87,17 +87,17 @@ The following groups correspond to the header groups in the style guide. If a he

Appending a `// NOLINT` comment to a header include to prevent wpiformat's header include sorter from modifying it and to maintain its relative ordering with other header includes. This will, in effect, treat it as a barrier across which no header includes will be moved. Header includes on each side of the barrier will still be sorted as normal.

## .styleguide-license
## .wpiformat-license

This file contains the license header template. It should contain `Copyright (c)` followed by the company name and the string `{year}`. See the `.styleguide-license` file in the docs/examples directory.
This file contains the license header template. It should contain `Copyright (c)` followed by the company name and the string `{year}`. See the `.wpiformat-license` file in the docs/examples directory.

wpiformat checks the currently processed file's directory for a `.styleguide` file first and traverses up the directory tree if one isn't found. This allows templates which are closer to the processed file to override a project's main template.
wpiformat checks the currently processed file's directory for a `.wpiformat` file first and traverses up the directory tree if one isn't found. This allows templates which are closer to the processed file to override a project's main template.

### License header semantics

The license header is always at the beginning of the file and ends after two newlines. If there isn't one, or it doesn't contain the required copyright contents, wpiformat inserts a new one containing the current year.

### `.styleguide-license` special variables
### `.wpiformat-license` special variables

`{year}` is replaced with a year range from the earliest copyright year in the file to the current year. If the earliest year is the current year, only that year will be written.

Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion wpiformat/test/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


def test_config():
config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
config_file = Config(os.path.abspath(os.getcwd()), ".wpiformat")
assert config_file.is_modifiable_file(
"." + os.sep + "wpiformat" + os.sep + "javaguidelink.png"
)
Expand Down
10 changes: 5 additions & 5 deletions wpiformat/test/test_licenseupdate.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,20 +307,20 @@ def test_licenseupdate():
)

# Ensure excluded files won't be processed
config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
config_file = Config(os.path.abspath(os.getcwd()), ".wpiformat")
assert not task.should_process_file(config_file, "./Excluded.h")

# Create git repo to test license years for commits
with OpenTemporaryDirectory():
subprocess.run(["git", "init", "-q"])

# Add base files
with open(".styleguide-license", "w") as file:
with open(".wpiformat-license", "w") as file:
file.write("// Copyright (c) {year}")
with open(".styleguide", "w") as file:
with open(".wpiformat", "w") as file:
file.write("cppSrcFileInclude {\n" + r"\.cpp$")
subprocess.run(["git", "add", ".styleguide-license"])
subprocess.run(["git", "add", ".styleguide"])
subprocess.run(["git", "add", ".wpiformat-license"])
subprocess.run(["git", "add", ".wpiformat"])
subprocess.run(["git", "commit", "-q", "-m", '"Initial commit"'])

# Add file with commit date of last year and range through this year
Expand Down
2 changes: 1 addition & 1 deletion wpiformat/test/test_tasktest.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def run(self, output_type):
"""
assert len(self.inputs) == len(self.outputs)

config_file = Config(os.path.abspath(os.getcwd()), ".styleguide")
config_file = Config(os.path.abspath(os.getcwd()), ".wpiformat")

for i in range(len(self.inputs)):
if self.task.should_process_file(config_file, self.inputs[i][0]):
Expand Down
38 changes: 34 additions & 4 deletions wpiformat/wpiformat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,16 @@ def proc_pipeline(name):
Keyword arguments:
name -- file name string
"""
config_file = Config(os.path.dirname(name), ".styleguide")
try:
config_file = Config(os.path.dirname(name), ".wpiformat")
except OSError:
print(
"Warning: '.wpiformat' file not found. Looking for deprecated '.styleguide' file."
)
# TODO: Remove handling for deprecated .styleguide file
config_file = Config(os.path.dirname(name), ".styleguide")
print("Warning: found deprecated '.styleguide' file. Rename to '.wpiformat'.")

if verbose1 or verbose2:
with print_lock:
print("Processing", name)
Expand Down Expand Up @@ -129,7 +138,13 @@ def proc_standalone(name):
Keyword arguments:
name -- file name string
"""
config_file = Config(os.path.dirname(name), ".styleguide")
try:
config_file = Config(os.path.dirname(name), ".wpiformat")
except OSError:
# TODO: Remove handling for deprecated .styleguide file
config_file = Config(os.path.dirname(name), ".styleguide")
print("Warning: found deprecated '.styleguide' file. Rename to '.wpiformat'.")

if verbose2:
with print_lock:
print("Processing", name)
Expand Down Expand Up @@ -179,7 +194,15 @@ def proc_batch(files):
for subtask in task_pipeline:
work = []
for name in files:
config_file = Config(os.path.dirname(name), ".styleguide")
try:
config_file = Config(os.path.dirname(name), ".wpiformat")
except OSError:
# TODO: Remove handling for deprecated .styleguide file
config_file = Config(os.path.dirname(name), ".styleguide")
print(
"Warning: found deprecated '.styleguide' file. Rename to '.wpiformat'."
)

if subtask.should_process_file(config_file, name):
work.append(name)

Expand Down Expand Up @@ -480,7 +503,14 @@ def main():
# Don't run tasks on modifiable or generated files
work = []
for name in files:
config_file = Config(os.path.dirname(name), ".styleguide")
try:
config_file = Config(os.path.dirname(name), ".wpiformat")
except OSError:
# TODO: Remove handling for deprecated .styleguide file
config_file = Config(os.path.dirname(name), ".styleguide")
print(
"Warning: found deprecated '.styleguide' file. Rename to '.wpiformat'."
)

if config_file.is_modifiable_file(name):
continue
Expand Down
35 changes: 17 additions & 18 deletions wpiformat/wpiformat/config.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
"""This class is for handling wpiformat config files."""

import os
import sys

import regex


class Config:
# Dict from filepath to file contents
config_cache: dict[str, list[str]] = {}

def __init__(self, directory, file_name):
"""Constructor for Config object.

Expand Down Expand Up @@ -35,26 +37,23 @@ def read_file(directory, file_name):
Returns tuple of file name and list containing file contents or triggers
program exit.
"""
file_found = False
while not file_found:
while True:
filepath = os.path.join(directory, file_name)
try:
with open(directory + os.sep + file_name, "r") as file_contents:
file_found = True
return (
os.path.join(directory, file_name),
file_contents.read().splitlines(),
)
except OSError:
# If filepath in config cache, return cached version instead
if filepath in Config.config_cache:
return filepath, Config.config_cache[filepath]

with open(filepath, "r") as file_contents:
contents = file_contents.read().splitlines()
Config.config_cache[filepath] = contents
return filepath, contents
except OSError as e:
# .git files are ignored, which are created within submodules
if os.path.isdir(directory + os.sep + ".git"):
print(
"Error: config file '"
+ file_name
+ "' not found in '"
+ directory
+ "'"
)
sys.exit(1)
raise OSError(
f"config file '{file_name}' not found in '{directory}'"
) from e
directory = os.path.dirname(directory)

def group(self, group_name):
Expand Down
15 changes: 12 additions & 3 deletions wpiformat/wpiformat/licenseupdate.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,18 @@ def __try_string_search(self, lines, last_year, license_template):
def run_pipeline(self, config_file, name, lines):
linesep = super().get_linesep(lines)

_, license_template = Config.read_file(
os.path.dirname(os.path.abspath(name)), ".styleguide-license"
)
try:
_, license_template = Config.read_file(
os.path.dirname(os.path.abspath(name)), ".wpiformat-license"
)
except OSError:
# TODO: Remove handling for deprecated .styleguide-license file
_, license_template = Config.read_file(
os.path.dirname(os.path.abspath(name)), ".styleguide-license"
)
print(
"Warning: found deprecated '.styleguide-license' file. Rename to '.wpiformat-license'."
)

# Get year when file was most recently modified in Git history
#
Expand Down