Skip to content

Commit b0ea7f6

Browse files
authored
Autodetect line endings in the file (#215)
* run black * detect and preserve line endings
1 parent 4513358 commit b0ea7f6

File tree

13 files changed

+98
-20
lines changed

13 files changed

+98
-20
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@
2121
- Non default transformers can be enabled using ``enabled=True`` parameter ([#182](https://github.com/MarketSquare/robotframework-tidy/issues/182))
2222
- Semicolon in parameter value can now be escaped with `\:` ([#190](https://github.com/MarketSquare/robotframework-tidy/issues/190))
2323
- Default separator can be changed from space to tabular with new ``--separator`` option ([#184](https://github.com/MarketSquare/robotframework-tidy/issues/184))
24+
- ``--lineseparator`` option now accepts `auto` value for preserving line endings found in the file ([#209](https://github.com/MarketSquare/robotframework-tidy/issues/209))
2425

2526
### Fixes
2627
- Robotidy will not print "Loaded configuration from ... " if the configuration is empty ([#193](https://github.com/MarketSquare/robotframework-tidy/issues/193))
28+
- no source path provided error now exits with code 1 instead of 0 ([#208](https://github.com/MarketSquare/robotframework-tidy/issues/208))
2729

2830
### Other
2931
- ReplaceRunKeywordIf now removes ELSE branch if it is unnecessary ([#192](https://github.com/MarketSquare/robotframework-tidy/issues/192))

robotidy/app.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import sys
23
from collections import defaultdict
34
from difflib import unified_diff
@@ -24,8 +25,8 @@ def __init__(
2425
transformers: List[Tuple[str, List]],
2526
transformers_config: List[Tuple[str, List]],
2627
src: Tuple[str, ...],
27-
exclude: Pattern,
28-
extend_exclude: Pattern,
28+
exclude: Optional[Pattern],
29+
extend_exclude: Optional[Pattern],
2930
overwrite: bool,
3031
show_diff: bool,
3132
formatting_config: GlobalFormattingConfig,
@@ -68,7 +69,7 @@ def transform_files(self):
6869
if stdin:
6970
self.print_to_stdout(new_model)
7071
else:
71-
self.save_model(model)
72+
self.save_model(model.source, model)
7273
except DataError:
7374
click.echo(
7475
f"Failed to decode {source}. Default supported encoding by Robot Framework is UTF-8. Skipping file"
@@ -93,10 +94,22 @@ def print_to_stdout(self, collected_lines):
9394
if not self.show_diff:
9495
click.echo(collected_lines.text)
9596

96-
def save_model(self, model):
97+
def save_model(self, source, model):
9798
if self.overwrite:
9899
output = self.output or model.source
99-
ModelWriter(output=output, newline=self.formatting_config.line_sep).write(model)
100+
ModelWriter(output=output, newline=self.get_line_ending(source)).write(model)
101+
102+
def get_line_ending(self, path: str):
103+
if self.formatting_config.line_sep == "auto":
104+
with open(path) as f:
105+
f.readline()
106+
if f.newlines is None:
107+
return os.linesep
108+
if isinstance(f.newlines, str):
109+
return f.newlines
110+
else:
111+
return f.newlines[0]
112+
return self.formatting_config.line_sep
100113

101114
def output_diff(
102115
self,

robotidy/cli.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -254,12 +254,13 @@ def print_transformers_list():
254254
@click.option(
255255
"-ls",
256256
"--lineseparator",
257-
type=click.types.Choice(["native", "windows", "unix"]),
257+
type=click.types.Choice(["native", "windows", "unix", "auto"]),
258258
default="native",
259259
help="Line separator to use in outputs.\n"
260-
"native: use operating system's native line separators\n"
261-
"windows: use Windows line separators (CRLF)\n"
262-
"unix: use Unix line separators (LF)",
260+
"native: use operating system's native line endings\n"
261+
"windows: use Windows line endings (CRLF)\n"
262+
"unix: use Unix line endings (LF)\n"
263+
"auto: maintain existing line endings (uses what's used in the first line)",
263264
show_default=True,
264265
)
265266
@click.option(

robotidy/files.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def path_is_excluded(
9292
return bool(match and match.group(0))
9393

9494

95-
def get_paths(src: Tuple[str, ...], exclude: Pattern, extend_exclude: Optional[Pattern]):
95+
def get_paths(src: Tuple[str, ...], exclude: Optional[Pattern], extend_exclude: Optional[Pattern]):
9696
root = find_project_root(src)
9797
gitignore = get_gitignore(root)
9898
sources = set()
@@ -113,16 +113,16 @@ def get_paths(src: Tuple[str, ...], exclude: Pattern, extend_exclude: Optional[P
113113

114114
def iterate_dir(
115115
paths: Iterable[Path],
116-
exclude: Pattern,
117-
extend_exclude: Pattern,
116+
exclude: Optional[Pattern],
117+
extend_exclude: Optional[Pattern],
118118
gitignore: Optional[PathSpec],
119119
) -> Iterator[Path]:
120120
for path in paths:
121121
if gitignore is not None and gitignore.match_file(path):
122122
continue
123123
if path_is_excluded(str(path), exclude) or path_is_excluded(str(path), extend_exclude):
124124
continue
125-
if path.is_dir() and not exclude.match(path.name):
125+
if path.is_dir() and exclude and not exclude.match(path.name):
126126
yield from iterate_dir(
127127
path.iterdir(),
128128
exclude,

robotidy/utils.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import os
22
import ast
3-
from typing import List
3+
from typing import List, Optional
44
import difflib
55

66
from robot.api.parsing import ModelVisitor, Token
@@ -31,8 +31,8 @@ def __init__(
3131
self,
3232
space_count: int,
3333
line_sep: str,
34-
start_line: int,
35-
end_line: int,
34+
start_line: Optional[int],
35+
end_line: Optional[int],
3636
separator: str,
3737
):
3838
self.start_line = start_line
@@ -49,6 +49,8 @@ def __init__(
4949
self.line_sep = "\r\n"
5050
elif line_sep == "unix":
5151
self.line_sep = "\n"
52+
elif line_sep == "auto":
53+
self.line_sep = "auto"
5254
else:
5355
self.line_sep = os.linesep
5456

tests/utest/test_utils.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,41 @@
1+
import os
2+
from pathlib import Path
3+
14
import pytest
5+
6+
from robotidy.app import Robotidy
27
from robotidy.utils import (
38
decorate_diff_with_color,
4-
split_args_from_name_or_path
9+
split_args_from_name_or_path,
10+
GlobalFormattingConfig
511
)
612

713

14+
@pytest.fixture
15+
def app():
16+
formatting_config = GlobalFormattingConfig(
17+
space_count=4,
18+
line_sep="auto",
19+
start_line=None,
20+
separator="space",
21+
end_line=None,
22+
)
23+
return Robotidy(
24+
transformers=[],
25+
transformers_config=[],
26+
src=('.',),
27+
exclude=None,
28+
extend_exclude=None,
29+
overwrite=False,
30+
show_diff=False,
31+
formatting_config=formatting_config,
32+
verbose=False,
33+
check=False,
34+
output=None,
35+
force_order=False
36+
)
37+
38+
839
class TestUtils:
940
def test_not_changed_lines_not_colorized(self):
1041
lines = [
@@ -49,3 +80,27 @@ def test_split_args_from_name_or_path(self, name_or_path, expected_name, expecte
4980
name, args = split_args_from_name_or_path(name_or_path)
5081
assert name == expected_name
5182
assert args == expected_args
83+
84+
@pytest.mark.parametrize("line_sep, source_file, expected", [
85+
("auto", "lf.robot", "\n"),
86+
("auto", "crlf.robot", "\r\n"),
87+
("auto", "cr.robot", "\r"),
88+
("auto", "crlf_mixed.robot", "\n"),
89+
("auto", "empty.robot", os.linesep),
90+
("native", "lf.robot", os.linesep),
91+
("native", "crlf.robot", os.linesep),
92+
("windows", "lf.robot", "\r\n"),
93+
("windows", "crlf.robot", "\r\n"),
94+
("unix", "lf.robot", "\n"),
95+
("unix", "crlf.robot", "\n")
96+
])
97+
def test_get_line_ending(self, line_sep, source_file, expected, app):
98+
source = str(Path(__file__).parent / 'testdata' / 'auto_line_sep' / source_file)
99+
app.formatting_config = GlobalFormattingConfig(
100+
space_count=4,
101+
line_sep=line_sep,
102+
start_line=None,
103+
separator="space",
104+
end_line=None,
105+
)
106+
assert app.get_line_ending(source) == expected
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.robot -text

tests/utest/testdata/auto_line_sep/cr.robot

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*** Settings ***Library stuff.py
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*** Settings ***
2+
Library stuff.py
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*** Settings ***
2+
Library stuff.py

0 commit comments

Comments
 (0)