|
1 | 1 | """Collecting fragments.""" |
2 | 2 |
|
3 | | -import collections |
4 | | -import datetime |
5 | | -import itertools |
6 | 3 | import logging |
7 | | -from pathlib import Path |
8 | | -from typing import Dict, Iterable, List, Optional, Sequence, Tuple, TypeVar |
| 4 | +from typing import Optional |
9 | 5 |
|
10 | 6 | import click |
11 | 7 | import click_log |
12 | | -import jinja2 |
13 | 8 |
|
14 | | -from .config import Config |
15 | | -from .format import SectionDict, get_format_tools |
16 | 9 | from .gitinfo import git_add, git_config_bool, git_edit, git_rm |
| 10 | +from .scriv import Scriv |
17 | 11 |
|
18 | 12 | logger = logging.getLogger() |
19 | 13 |
|
20 | 14 |
|
21 | | -def files_to_combine(config: Config) -> List[Path]: |
22 | | - """ |
23 | | - Find all the files to be combined. |
24 | | -
|
25 | | - The files are returned in the order they should be processed. |
26 | | -
|
27 | | - """ |
28 | | - return sorted( |
29 | | - itertools.chain.from_iterable( |
30 | | - [ |
31 | | - Path(config.fragment_directory).glob(pattern) |
32 | | - for pattern in ["*.rst", "*.md"] |
33 | | - ] |
34 | | - ) |
35 | | - ) |
36 | | - |
37 | | - |
38 | | -def sections_from_file(config: Config, filename: Path) -> SectionDict: |
39 | | - """ |
40 | | - Collect the sections from a file. |
41 | | - """ |
42 | | - format_tools = get_format_tools(filename.suffix.lstrip("."), config) |
43 | | - text = filename.read_text().rstrip() |
44 | | - file_sections = format_tools.parse_text(text) |
45 | | - return file_sections |
46 | | - |
47 | | - |
48 | | -def combine_sections(config: Config, files: Iterable[Path]) -> SectionDict: |
49 | | - """ |
50 | | - Read files, and produce a combined SectionDict of their contents. |
51 | | - """ |
52 | | - sections = collections.defaultdict(list) # type: SectionDict |
53 | | - for file in files: |
54 | | - file_sections = sections_from_file(config, file) |
55 | | - for section, paragraphs in file_sections.items(): |
56 | | - sections[section].extend(paragraphs) |
57 | | - return sections |
58 | | - |
59 | | - |
60 | | -T = TypeVar("T") |
61 | | -K = TypeVar("K") |
62 | | - |
63 | | - |
64 | | -def order_dict( |
65 | | - d: Dict[Optional[K], T], keys: Sequence[Optional[K]] |
66 | | -) -> Dict[Optional[K], T]: |
67 | | - """ |
68 | | - Produce an OrderedDict of `d`, but with the keys in `keys` order. |
69 | | - """ |
70 | | - with_order = collections.OrderedDict() |
71 | | - to_insert = set(d) |
72 | | - for k in keys: |
73 | | - if k not in to_insert: |
74 | | - continue |
75 | | - with_order[k] = d[k] |
76 | | - to_insert.remove(k) |
77 | | - |
78 | | - for k in to_insert: |
79 | | - with_order[k] = d[k] |
80 | | - |
81 | | - return with_order |
82 | | - |
83 | | - |
84 | | -def cut_at_line(text: str, marker: str) -> Tuple[str, str]: |
85 | | - """ |
86 | | - Split text into two parts: up to the line with marker, and lines after. |
87 | | -
|
88 | | - If `marker` isn't in the text, return ("", text) |
89 | | - """ |
90 | | - lines = text.splitlines(keepends=True) |
91 | | - for i, line in enumerate(lines): |
92 | | - if marker in line: |
93 | | - return "".join(lines[: i + 1]), "".join(lines[i + 1 :]) |
94 | | - return ("", text) |
95 | | - |
96 | | - |
97 | 15 | @click.command() |
98 | 16 | @click.option( |
99 | 17 | "--add/--no-add", default=None, help="'git add' the updated changelog file." |
@@ -121,55 +39,27 @@ def collect( |
121 | 39 | if edit is None: |
122 | 40 | edit = git_config_bool("scriv.collect.edit") |
123 | 41 |
|
124 | | - config = Config.read() |
125 | | - logger.info("Collecting from {}".format(config.fragment_directory)) |
126 | | - files = files_to_combine(config) |
127 | | - sections = combine_sections(config, files) |
128 | | - sections = order_dict(sections, [None] + config.categories) |
| 42 | + scriv = Scriv() |
| 43 | + logger.info("Collecting from {}".format(scriv.config.fragment_directory)) |
| 44 | + frags = scriv.fragments_to_combine() |
129 | 45 |
|
130 | | - changelog = Path(config.output_file) |
131 | | - newline = "" |
132 | | - if changelog.exists(): |
133 | | - with changelog.open("r") as f: |
134 | | - changelog_text = f.read() |
135 | | - if f.newlines: # .newlines may be None, str, or tuple |
136 | | - if isinstance(f.newlines, str): |
137 | | - newline = f.newlines |
138 | | - else: |
139 | | - newline = f.newlines[0] |
140 | | - text_before, text_after = cut_at_line( |
141 | | - changelog_text, config.insert_marker |
142 | | - ) |
143 | | - else: |
144 | | - text_before = "" |
145 | | - text_after = "" |
| 46 | + changelog = scriv.changelog() |
| 47 | + changelog.read() |
146 | 48 |
|
147 | | - format_tools = get_format_tools(config.format, config) |
148 | | - title_data = { |
149 | | - "date": datetime.datetime.now(), |
150 | | - "version": version or config.version, |
151 | | - } |
152 | | - new_title = jinja2.Template(config.entry_title_template).render( |
153 | | - config=config, **title_data |
154 | | - ) |
155 | | - if new_title.strip(): |
156 | | - new_header = format_tools.format_header(new_title) |
157 | | - else: |
158 | | - new_header = "" |
159 | | - new_text = format_tools.format_sections(sections) |
160 | | - with changelog.open("w", newline=newline or None) as f: |
161 | | - f.write(text_before + new_header + new_text + text_after) |
| 49 | + new_header = changelog.entry_header(version=version) |
| 50 | + new_text = changelog.entry_text(scriv.combine_fragments(frags)) |
| 51 | + changelog.write(new_header, new_text) |
162 | 52 |
|
163 | 53 | if edit: |
164 | | - git_edit(changelog) |
| 54 | + git_edit(changelog.path) |
165 | 55 |
|
166 | 56 | if add: |
167 | | - git_add(changelog) |
| 57 | + git_add(changelog.path) |
168 | 58 |
|
169 | 59 | if not keep: |
170 | | - for file in files: |
171 | | - logger.info("Deleting fragment file {}".format(file)) |
| 60 | + for frag in frags: |
| 61 | + logger.info("Deleting fragment file {!r}".format(str(frag.path))) |
172 | 62 | if add: |
173 | | - git_rm(file) |
| 63 | + git_rm(frag.path) |
174 | 64 | else: |
175 | | - file.unlink() |
| 65 | + frag.path.unlink() |
0 commit comments