haraka 0.2.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- haraka/__init__.py +4 -0
- haraka/art/__init__.py +3 -0
- haraka/art/ascii/__init__.py +0 -0
- haraka/art/ascii/assets.py +200 -0
- haraka/art/ascii/frame/__init__.py +5 -0
- haraka/art/ascii/frame/border.py +44 -0
- haraka/art/ascii/frame/framer.py +125 -0
- haraka/art/ascii/frame/width_utils.py +30 -0
- haraka/art/create.py +17 -0
- haraka/post_gen/__init__.py +0 -0
- haraka/post_gen/config/__init__.py +3 -0
- haraka/post_gen/config/config.py +11 -0
- haraka/post_gen/runner.py +54 -0
- haraka/post_gen/utils/__init__.py +0 -0
- haraka/post_gen/utils/assets.py +204 -0
- haraka/post_gen/utils/command.py +49 -0
- haraka/post_gen/utils/files.py +46 -0
- haraka/post_gen/utils/gitops.py +60 -0
- haraka/post_gen/utils/purge.py +70 -0
- haraka/utils/__init__.py +5 -0
- haraka/utils/common/__init__.py +0 -0
- haraka/utils/common/utils.py +14 -0
- haraka/utils/logging/__init__.py +0 -0
- haraka/utils/logging/log_util.py +28 -0
- haraka-0.2.5.dist-info/METADATA +14 -0
- haraka-0.2.5.dist-info/RECORD +28 -0
- haraka-0.2.5.dist-info/WHEEL +5 -0
- haraka-0.2.5.dist-info/top_level.txt +1 -0
haraka/__init__.py
ADDED
haraka/art/__init__.py
ADDED
File without changes
|
@@ -0,0 +1,200 @@
|
|
1
|
+
goLang = f"""
|
2
|
+
\u200B ____ _ \u200B
|
3
|
+
\u200B / ___| ___ | | __ _ _ __ __ _ \u200B
|
4
|
+
\u200B | | _ / _ \| | / _` | '_ \ / _` | \u200B
|
5
|
+
\u200B | |_| | (_) | |__| (_| | | | | (_| | \u200B
|
6
|
+
\u200B \____|\___/|_____\__,_|_| |_|\__, | \u200B
|
7
|
+
\u200B |___/ \u200B
|
8
|
+
"""
|
9
|
+
protoC_Mode = """
|
10
|
+
\u200B ____ _ ____ __ __ _ \u200B
|
11
|
+
\u200B | _ \ _ __ ___ | |_ ___ / ___| | \/ | ___ __| | ___ \u200B
|
12
|
+
\u200B | |_) | '__/ _ \| __/ _ \| | | |\/| |/ _ \ / _` |/ _ \ \u200B
|
13
|
+
\u200B | __/| | | (_) | || (_) | |___ | | | | (_) | (_| | __/ \u200B
|
14
|
+
\u200B |_| |_| \___/ \__\___/ \____| |_| |_|\___/ \__,_|\___| \u200B
|
15
|
+
"""
|
16
|
+
goFast = f"""
|
17
|
+
\u200B ____ ___ _____ _ ____ _____ \u200B
|
18
|
+
\u200B / ___|/ _ \ | ___|/ \ / ___| _ _| \u200B
|
19
|
+
\u200B | | _| | | | | |__ / _ \ \___ \ | | \u200B
|
20
|
+
\u200B | |_| | |_| | | |__/ ___ \ ___) | | | \u200B
|
21
|
+
\u200B \___/ \___ / |_| /_/ \_\____/ |_| \u200B
|
22
|
+
"""
|
23
|
+
|
24
|
+
emoji = {
|
25
|
+
"goFast": f"""
|
26
|
+
\u200B π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π© \u200B
|
27
|
+
\u200B π©π©β¬β¬β¬β¬π©π©π©β¬β¬β¬π©π©π©β¬β¬β¬β¬β¬π©π©π©π©β¬π©π©π©π©π©β¬β¬β¬β¬π©π©β¬β¬β¬β¬β¬π© \u200B
|
28
|
+
\u200B π©β¬π©π©π©π©π©π©β¬π©π©π©β¬π©π©β¬π©π©π©π©π©π©π©β¬π©β¬π©π©π©β¬π©π©π©π©π©π©π©π©β¬π©π©π© \u200B
|
29
|
+
\u200B π©β¬π©π©β¬β¬π©π©β¬π©π©π©β¬π©π©β¬β¬β¬β¬π©π©π©β¬π©π©π©β¬π©π©π©β¬β¬β¬π©π©π©π©π©β¬π©π©π© \u200B
|
30
|
+
\u200B π©β¬π©π©π©β¬π©π©β¬π©π©π©β¬π©π©β¬π©π©π©π©π©π©β¬β¬β¬β¬β¬π©π©π©π©π©π©β¬π©π©π©π©β¬π©π©π© \u200B
|
31
|
+
\u200B π©π©β¬β¬β¬β¬π©π©π©β¬β¬β¬π©π©π©β¬π©π©π©π©π©π©β¬π©π©π©β¬π©π©β¬β¬β¬β¬π©π©π©π©π©β¬π©π©π© \u200B
|
32
|
+
\u200B π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π©π© \u200B
|
33
|
+
""",
|
34
|
+
"go": f"""
|
35
|
+
\u200Bπ©π©π©π©π©π©π©π©π©π©π©π©π©π©\u200B
|
36
|
+
\u200Bπ©π©β¬β¬β¬β¬π©π©π©β¬β¬β¬π©π©\u200B
|
37
|
+
\u200Bπ©β¬π©π©π©π©π©π©β¬π©π©π©β¬π©\u200B
|
38
|
+
\u200Bπ©β¬π©π©β¬β¬π©π©β¬π©π©π©β¬π©\u200B
|
39
|
+
\u200Bπ©β¬π©π©π©β¬π©π©β¬π©π©π©β¬π©\u200B
|
40
|
+
\u200Bπ©π©β¬β¬β¬β¬π©π©π©β¬β¬β¬π©π©\u200B
|
41
|
+
\u200Bπ©π©π©π©π©π©π©π©π©π©π©π©π©π©\u200B
|
42
|
+
"""
|
43
|
+
}
|
44
|
+
|
45
|
+
gRpc_ProtoBuf = f"""
|
46
|
+
\u200B ____ ____ ____ ____ _ ____ __ \u200B
|
47
|
+
\u200B __ _| _ \| _ \ / ___| | _ \ _ __ ___ | |_ ___ | __ ) _ _ / _| \u200B
|
48
|
+
\u200B / _` | |_) | |_) | | _____| |_) | '__/ _ \| __/ _ \| _ \| | | | |_| \u200B
|
49
|
+
\u200B | (_| | _ <| __/| |__|_____| __/| | | (_) | || (_) | |_) | |_| | _| \u200B
|
50
|
+
\u200B \__, |_| \_\_| \____| |_| |_| \___/ \__\___/|____/ \__,_|_| \u200B
|
51
|
+
\u200B |___/ \u200B
|
52
|
+
"""
|
53
|
+
swaggerUI = """
|
54
|
+
\u200B ____ _ _ ___ \u200B
|
55
|
+
\u200B / ___|_ ____ _ __ _ __ _ ___ _ __| | | |_ _| \u200B
|
56
|
+
\u200B \___ \ \ /\ / / _` |/ _` |/ _` |/ _ \ '__| | | || | \u200B
|
57
|
+
\u200B ___) \ V V / (_| | (_| | (_| | __/ | | |_| || | \u200B
|
58
|
+
\u200B |____/ \_/\_/ \__,_|\__, |\__, |\___|_| \___/|___| \u200B
|
59
|
+
\u200B |___/ |___/ \u200B
|
60
|
+
"""
|
61
|
+
server = """
|
62
|
+
\u200B ____ \u200B
|
63
|
+
\u200B / ___| ___ _ ____ _____ _ __ \u200B
|
64
|
+
\u200B \___ \ / _ \ '__\ \ / / _ \ '__| \u200B
|
65
|
+
\u200B ___) | __/ | \ V / __/ | \u200B
|
66
|
+
\u200B |____/ \___|_| \_/ \___|_| \u200B
|
67
|
+
"""
|
68
|
+
divider_mono = f"""
|
69
|
+
\u200B _____ \u200B
|
70
|
+
\u200B |_____| \u200B
|
71
|
+
"""
|
72
|
+
divider_xs = f"""
|
73
|
+
\u200B _____ _____ \u200B
|
74
|
+
\u200B |_____|_____| \u200B
|
75
|
+
"""
|
76
|
+
divider_s = f"""
|
77
|
+
\u200B _____ _____ _____ \u200B
|
78
|
+
\u200B |_____|_____|_____| \u200B
|
79
|
+
"""
|
80
|
+
divider_m = f"""
|
81
|
+
\u200B _____ _____ _____ _____ _____ \u200B
|
82
|
+
\u200B |_____|_____|_____|_____|_____| \u200B
|
83
|
+
"""
|
84
|
+
divider_l = f"""
|
85
|
+
\u200B _____ _____ _____ _____ _____ _____ _____ _____ \u200B
|
86
|
+
\u200B |_____|_____|_____|_____|_____|_____|_____|_____| \u200B
|
87
|
+
"""
|
88
|
+
divider_xl = f"""
|
89
|
+
\u200B _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ \u200B
|
90
|
+
\u200B |_____|_____|_____|_____|_____|_____|_____|_____|_____|_____|_____|_____|_____| \u200B
|
91
|
+
"""
|
92
|
+
by_google = f"""
|
93
|
+
\u200B _ ____ _ \u200B
|
94
|
+
\u200B | |__ _ _ / ___| ___ ___ __ _| | ___ \u200B
|
95
|
+
\u200B | '_ \| | | | | | _ / _ \ / _ \ / _` | |/ _ \ \u200B
|
96
|
+
\u200B | |_) | |_| | | |_| | (_) | (_) | (_| | | __/ \u200B
|
97
|
+
\u200B |_.__/ \__, | \____|\___/ \___/ \__, |_|\___| \u200B
|
98
|
+
\u200B |___/ |___/ \u200B
|
99
|
+
"""
|
100
|
+
by = """
|
101
|
+
\u200B _____ _ __ \u200B
|
102
|
+
\u200B | __ ) \ / / \u200B
|
103
|
+
\u200B | _ \ \ V / \u200B
|
104
|
+
\u200B | |_) | | | \u200B
|
105
|
+
\u200B |____/ |_| \u200B
|
106
|
+
"""
|
107
|
+
wjb_dev = f"""
|
108
|
+
\u200B __ __ _ ____ ____ _______ __ \u200B
|
109
|
+
\u200B \ \ / / | | __ ) | _ \| ____\ \ / / \u200B
|
110
|
+
\u200B \ \ /\ / / | | _ \ | | | | _| \ \ / / \u200B
|
111
|
+
\u200B \ V V / |_| | |_) || |_| | |___ \ V / \u200B
|
112
|
+
\u200B \_/\_/ \___/|____(_)____/|_____| \_/ \u200B
|
113
|
+
"""
|
114
|
+
|
115
|
+
gRPCurl = f"""
|
116
|
+
\u200B ____ ____ ____ _ \u200B
|
117
|
+
\u200B __ _| _ \| _ \ / ___| _ _ __| | \u200B
|
118
|
+
\u200B / _` | |_) | |_) | | | | | | '__| | \u200B
|
119
|
+
\u200B | (_| | _ <| __/| |__| |_| | | | | \u200B
|
120
|
+
\u200B \__, |_| \_\_| \____\__,_|_| |_| \u200B
|
121
|
+
\u200B |___/ \u200B
|
122
|
+
"""
|
123
|
+
zeroLog = """
|
124
|
+
\u200B _____ _ \u200B
|
125
|
+
\u200B |__ /___ _ __ ___ | | ___ __ _ \u200B
|
126
|
+
\u200B / // _ \ '__/ _ \| | / _ \ / _` | \u200B
|
127
|
+
\u200B / /| __/ | | (_) | |__| (_) | (_| | \u200B
|
128
|
+
\u200B /____\___|_| \___/|_____\___/ \__, | \u200B
|
129
|
+
\u200B |___/ \u200B
|
130
|
+
"""
|
131
|
+
gRPC = f"""
|
132
|
+
\u200B ____ ____ ____ \u200B
|
133
|
+
\u200B __ _| _ \| _ \ / ___| \u200B
|
134
|
+
\u200B / _` | |_) | |_) | | \u200B
|
135
|
+
\u200B | (_| | _ <| __/| |___ \u200B
|
136
|
+
\u200B \__, |_| \_\_| \____| \u200B
|
137
|
+
\u200B |___/ \u200B
|
138
|
+
"""
|
139
|
+
autoMaxProcs = f"""
|
140
|
+
\u200B _ _ __ __ ____ \u200B
|
141
|
+
\u200B / \ _ _| |_ ___ | \/ | __ ___ _| _ \ _ __ ___ ___ ___ \u200B
|
142
|
+
\u200B / _ \| | | | __/ _ \| |\/| |/ _` \ \/ / |_) | '__/ _ \ / __/ __| \u200B
|
143
|
+
\u200B / ___ \ |_| | || (_) | | | | (_| |> <| __/| | | (_) | (__\__ \ \u200B
|
144
|
+
\u200B /_/ \_\__,_|\__\___/|_| |_|\__,_/_/\_\_| |_| \___/ \___|___/ \u200B
|
145
|
+
"""
|
146
|
+
ants = f"""
|
147
|
+
\u200B _ _ \u200B
|
148
|
+
\u200B / \ _ __ | |_ ___ \u200B
|
149
|
+
\u200B / _ \ | '_ \| __/ __| \u200B
|
150
|
+
\u200B / ___ \| | | | |_\__ \ \u200B
|
151
|
+
\u200B /_/ \_\_| |_|\__|___/ \u200B
|
152
|
+
"""
|
153
|
+
protoC = f"""
|
154
|
+
\u200B ____ _ ____ \u200B
|
155
|
+
\u200B | _ \ _ __ ___ | |_ ___ / ___| \u200B
|
156
|
+
\u200B | |_) | '__/ _ \| __/ _ \| | \u200B
|
157
|
+
\u200B | __/| | | (_) | || (_) | |___ \u200B
|
158
|
+
\u200B |_| |_| \___/ \__\___/ \____| \u200B
|
159
|
+
"""
|
160
|
+
performance_mode = """
|
161
|
+
\u200B ____ __ __ __ _ \u200B
|
162
|
+
\u200B | _ \ ___ _ __ / _| ___ _ __ _ __ ___ __ _ _ __ ___ ___ | \/ | ___ __| | ___ \u200B
|
163
|
+
\u200B | |_) / _ \ '__| |_ / _ \| '__| '_ ` _ \ / _` | '_ \ / __/ _ \ | |\/| |/ _ \ / _` |/ _ \ \u200B
|
164
|
+
\u200B | __/ __/ | | _| (_) | | | | | | | | (_| | | | | (_| __/ | | | | (_) | (_| | __/ \u200B
|
165
|
+
\u200B |_| \___|_| |_| \___/|_| |_| |_| |_|\__,_|_| |_|\___\___| |_| |_|\___/ \__,_|\___| \u200B
|
166
|
+
"""
|
167
|
+
tools = f"""
|
168
|
+
\u200B _____ _ \u200B
|
169
|
+
\u200B |_ _|__ ___ | |___ \u200B
|
170
|
+
\u200B | |/ _ \ / _ \| / __| \u200B
|
171
|
+
\u200B | | (_) | (_) | \__ \ \u200B
|
172
|
+
\u200B |_|\___/ \___/|_|___/ \u200B
|
173
|
+
"""
|
174
|
+
|
175
|
+
__all__ = [
|
176
|
+
"goLang",
|
177
|
+
"protoC_Mode",
|
178
|
+
"goFast",
|
179
|
+
"gRpc_ProtoBuf",
|
180
|
+
"swaggerUI",
|
181
|
+
"server",
|
182
|
+
"divider_mono",
|
183
|
+
"divider_xs",
|
184
|
+
"divider_s",
|
185
|
+
"divider_m",
|
186
|
+
"divider_l",
|
187
|
+
"divider_xl",
|
188
|
+
"by_google",
|
189
|
+
"by",
|
190
|
+
"wjb_dev",
|
191
|
+
"emoji",
|
192
|
+
"gRPCurl",
|
193
|
+
"zeroLog",
|
194
|
+
"gRPC",
|
195
|
+
"autoMaxProcs",
|
196
|
+
"ants",
|
197
|
+
"protoC",
|
198
|
+
"performance_mode",
|
199
|
+
"tools",
|
200
|
+
]
|
@@ -0,0 +1,44 @@
|
|
1
|
+
"""
|
2
|
+
Everything about the **horizontal** border (top / bottom).
|
3
|
+
"""
|
4
|
+
import shutil
|
5
|
+
|
6
|
+
|
7
|
+
class BorderBuilder:
|
8
|
+
"""
|
9
|
+
Builds a single horizontal line β optionally centred β that is
|
10
|
+
`pattern`-wide and `fraction` of the terminal width.
|
11
|
+
"""
|
12
|
+
|
13
|
+
def __init__(self, pattern: str = "=", fraction: float = 0.80, center: bool = True):
|
14
|
+
self.pattern = pattern
|
15
|
+
self.fraction = fraction
|
16
|
+
self.center = center
|
17
|
+
|
18
|
+
# ------- public API ------------------------------------------------ #
|
19
|
+
|
20
|
+
def build(self) -> str:
|
21
|
+
"""Return the fully formed border line."""
|
22
|
+
horiz = self._repeat_pattern(self.width)
|
23
|
+
|
24
|
+
if not self.center:
|
25
|
+
return horiz
|
26
|
+
|
27
|
+
margin = (self.term_width - self.width) // 2
|
28
|
+
return " " * margin + horiz if margin > 0 else horiz
|
29
|
+
|
30
|
+
# ------- internals -------------------------------------------------- #
|
31
|
+
|
32
|
+
@property
|
33
|
+
def term_width(self) -> int:
|
34
|
+
return max(1, shutil.get_terminal_size(fallback=(80, 24)).columns)
|
35
|
+
|
36
|
+
@property
|
37
|
+
def width(self) -> int:
|
38
|
+
return max(1, int(self.term_width * self.fraction))
|
39
|
+
|
40
|
+
def _repeat_pattern(self, target: int) -> str:
|
41
|
+
if not self.pattern:
|
42
|
+
return " " * target
|
43
|
+
reps = (target // len(self.pattern)) + 1
|
44
|
+
return (self.pattern * reps)[:target]
|
@@ -0,0 +1,125 @@
|
|
1
|
+
"""
|
2
|
+
High-level Β«drop-inΒ» that turns a list[str] into a fully framed banner.
|
3
|
+
"""
|
4
|
+
from __future__ import annotations
|
5
|
+
|
6
|
+
import shutil
|
7
|
+
import textwrap
|
8
|
+
from typing import List
|
9
|
+
|
10
|
+
from .border import BorderBuilder
|
11
|
+
|
12
|
+
|
13
|
+
class TextFramer:
|
14
|
+
"""
|
15
|
+
Build a rectangular frame:
|
16
|
+
|
17
|
+
β’ configurable borders (x / y chars)
|
18
|
+
β’ configurable padding and alignment
|
19
|
+
β’ automatically wraps lines to fit inside
|
20
|
+
|
21
|
+
Example
|
22
|
+
-------
|
23
|
+
>>> framer = TextFramer(border_char_x="=", border_char_y="|")
|
24
|
+
>>> print(framer.frame(["Hello", "world"]))
|
25
|
+
"""
|
26
|
+
|
27
|
+
def __init__(
|
28
|
+
self,
|
29
|
+
*,
|
30
|
+
border_char_x: str = "=",
|
31
|
+
border_char_y: str = "|",
|
32
|
+
padding: int = 1,
|
33
|
+
align: str = "center",
|
34
|
+
border_fraction: float = 0.80,
|
35
|
+
center_border: bool = True,
|
36
|
+
flex: bool = False,
|
37
|
+
art: str = ""
|
38
|
+
):
|
39
|
+
self.border_x = border_char_x
|
40
|
+
self.border_y = border_char_y
|
41
|
+
self.padding = max(0, padding)
|
42
|
+
self.align = align.lower()
|
43
|
+
self.border_fraction = border_fraction
|
44
|
+
self.center_border = center_border
|
45
|
+
self.flex = flex
|
46
|
+
|
47
|
+
# ---- public faΓ§ade ----------------------------------------------- #
|
48
|
+
|
49
|
+
def frame(self, texts: List[str]) -> str:
|
50
|
+
"""
|
51
|
+
Return one string with \n-separated lines ready for printing.
|
52
|
+
"""
|
53
|
+
lines = self._normalise(texts)
|
54
|
+
if not lines:
|
55
|
+
return ""
|
56
|
+
|
57
|
+
# 1οΈβ£ build top/bottom borders once
|
58
|
+
bb = BorderBuilder(self.border_x, self.border_fraction, self.center_border)
|
59
|
+
top_border = bb.build()
|
60
|
+
bottom_border = top_border # symmetrical
|
61
|
+
target_width = bb.width
|
62
|
+
if self.flex:
|
63
|
+
margin = (self.term_width - target_width) // 2 if self.center_border else 0
|
64
|
+
else :
|
65
|
+
margin = (110 - target_width) // 2 if self.center_border else 0
|
66
|
+
|
67
|
+
# 2οΈβ£ compute interior geometry
|
68
|
+
side = self.border_y or ""
|
69
|
+
side_w = len(side)
|
70
|
+
interior_w = max(1, target_width - 2 * side_w - 2 * self.padding)
|
71
|
+
|
72
|
+
# 3οΈβ£ iterate through wrapped chunks
|
73
|
+
frame: list[str] = [top_border]
|
74
|
+
for logical in lines:
|
75
|
+
chunks = textwrap.wrap(logical, width=interior_w) or [""]
|
76
|
+
for chunk in chunks:
|
77
|
+
frame.append(self._compose_line(chunk, interior_w, side, side_w, margin, target_width))
|
78
|
+
|
79
|
+
frame.append(bottom_border)
|
80
|
+
return "\n".join(frame)
|
81
|
+
|
82
|
+
# ---- helpers ------------------------------------------------------ #
|
83
|
+
|
84
|
+
@property
|
85
|
+
def term_width(self) -> int:
|
86
|
+
return max(1, shutil.get_terminal_size(fallback=(80, 24)).columns)
|
87
|
+
|
88
|
+
@staticmethod
|
89
|
+
def _normalise(texts: List[str]):
|
90
|
+
text = " ".join(texts)
|
91
|
+
return textwrap.dedent(text).strip("\n").splitlines()
|
92
|
+
|
93
|
+
# Build one interior line ------------------------------------------ #
|
94
|
+
def _compose_line(
|
95
|
+
self,
|
96
|
+
chunk: str,
|
97
|
+
interior_w: int,
|
98
|
+
side: str,
|
99
|
+
side_w: int,
|
100
|
+
margin: int,
|
101
|
+
target_w: int,
|
102
|
+
) -> str:
|
103
|
+
extra = interior_w - len(chunk)
|
104
|
+
if self.align == "left":
|
105
|
+
left_x, right_x = 0, extra
|
106
|
+
elif self.align == "right":
|
107
|
+
left_x, right_x = extra, 0
|
108
|
+
else: # centre
|
109
|
+
left_x, right_x = divmod(extra, 2)
|
110
|
+
|
111
|
+
left_pad = " " * (self.padding + left_x)
|
112
|
+
right_pad = " " * (self.padding + right_x)
|
113
|
+
body = f"{side}{left_pad}{chunk}{right_pad}{side}"
|
114
|
+
|
115
|
+
# pad / trim to exact width
|
116
|
+
if len(body) < target_w:
|
117
|
+
body = body[:-side_w] + " " * (target_w - len(body)) + body[-side_w:]
|
118
|
+
elif len(body) > target_w:
|
119
|
+
interior_allowed = target_w - 2 * side_w
|
120
|
+
body = f"{side}{body[side_w : side_w + interior_allowed]}{side}"
|
121
|
+
|
122
|
+
return " " * margin + body if margin else body
|
123
|
+
|
124
|
+
def generate(self, texts: List[str]):
|
125
|
+
return print(self.frame(texts))
|
@@ -0,0 +1,30 @@
|
|
1
|
+
"""
|
2
|
+
Helpers that deal with Unicode column widths and simple emoji detection.
|
3
|
+
"""
|
4
|
+
import logging
|
5
|
+
from wcwidth import wcwidth as _wcwidth
|
6
|
+
|
7
|
+
logger = logging.getLogger(__name__)
|
8
|
+
|
9
|
+
|
10
|
+
class WidthUtil:
|
11
|
+
"""Static helpers β no state required."""
|
12
|
+
|
13
|
+
@staticmethod
|
14
|
+
def wcwidth_narrow(ch: str) -> int:
|
15
|
+
"""
|
16
|
+
Return wcwidthβs value for *ch* (0, 1, or 2).
|
17
|
+
Keeping the wrapper separate makes unit-testing easier.
|
18
|
+
"""
|
19
|
+
return _wcwidth(ch)
|
20
|
+
|
21
|
+
@classmethod
|
22
|
+
def is_emoji_line(cls, text: str) -> bool:
|
23
|
+
"""
|
24
|
+
True if any code-point in *text* takes two columns (typical for emoji).
|
25
|
+
"""
|
26
|
+
for ch in text:
|
27
|
+
if cls.wcwidth_narrow(ch) > 1:
|
28
|
+
logger.info("%r β is emoji", text)
|
29
|
+
return True
|
30
|
+
return False
|
haraka/art/create.py
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
from haraka.art import TextFramer
|
2
|
+
|
3
|
+
class Create:
|
4
|
+
@staticmethod
|
5
|
+
def emoji(art: list[str], align: str = "left") -> None:
|
6
|
+
frame = TextFramer(border_char_x="", border_char_y="", padding=0, align=align)
|
7
|
+
frame.generate(art)
|
8
|
+
|
9
|
+
@staticmethod
|
10
|
+
def ascii(art: list[str], align: str = "left") -> None:
|
11
|
+
frame = TextFramer(border_char_x="=", border_char_y="||", padding=2, align=align)
|
12
|
+
frame.generate(art)
|
13
|
+
|
14
|
+
@staticmethod
|
15
|
+
def logo(art: list[str], align: str = "left") -> None:
|
16
|
+
frame = TextFramer(border_char_x="", border_char_y="", padding=2, align=align)
|
17
|
+
frame.generate(art)
|
File without changes
|
@@ -0,0 +1,54 @@
|
|
1
|
+
from post_gen.gen_ascii.ascii_art import goLang
|
2
|
+
|
3
|
+
from haraka.art.create import Create
|
4
|
+
from haraka.art.ascii.assets import *
|
5
|
+
from .config import PostGenConfig
|
6
|
+
from haraka.utils import divider, Logger
|
7
|
+
from haraka.post_gen.utils.command import CommandRunner
|
8
|
+
from haraka.post_gen.utils.files import FileOps
|
9
|
+
from haraka.post_gen.utils.purge import ResourcePurger
|
10
|
+
from haraka.post_gen.utils.gitops import GitOps
|
11
|
+
|
12
|
+
|
13
|
+
def main(cfg: PostGenConfig) -> None:
|
14
|
+
|
15
|
+
_logger = Logger(cfg.language)
|
16
|
+
logger = _logger.start_logger()
|
17
|
+
|
18
|
+
try:
|
19
|
+
cmd = CommandRunner(logger)
|
20
|
+
fops = FileOps(logger)
|
21
|
+
purge = ResourcePurger(fops, logger)
|
22
|
+
git = GitOps(cmd, logger)
|
23
|
+
except Exception as e:
|
24
|
+
logger.error(f"Failed to initialize components: {e}")
|
25
|
+
raise
|
26
|
+
|
27
|
+
divider("1οΈβ£ / 4οΈβ£ β Purge template junk")
|
28
|
+
purge.purge(cfg.language, cfg.project_dir)
|
29
|
+
|
30
|
+
divider("2οΈβ£ / 4οΈβ£ β Initialise Git repo")
|
31
|
+
git.init_repo(cfg.project_dir)
|
32
|
+
|
33
|
+
divider("3οΈβ£ / 4οΈβ£ β Commit scaffold")
|
34
|
+
git.stage_commit(cfg.project_dir)
|
35
|
+
|
36
|
+
divider("4οΈβ£ / 4οΈβ£ β Create GitHub repo & push")
|
37
|
+
git.push_to_github(cfg.project_dir, cfg.author, cfg.project_slug, cfg.description)
|
38
|
+
|
39
|
+
divider("π Project generation complete π")
|
40
|
+
|
41
|
+
if cfg.language == "go" and not cfg.swagger:
|
42
|
+
go_emoji_logo = [emoji.go]
|
43
|
+
go_performance_mode = [
|
44
|
+
goLang, divider_xl, performance_mode, divider_l, tools, divider_s,
|
45
|
+
gRPC, divider_mono, protoC, divider_mono, autoMaxProcs, divider_mono,
|
46
|
+
ants, divider_mono, zeroLog,
|
47
|
+
]
|
48
|
+
go_fast = [
|
49
|
+
goFast, gRpc_ProtoBuf, server,
|
50
|
+
by, wjb_dev
|
51
|
+
]
|
52
|
+
Create.emoji(go_emoji_logo)
|
53
|
+
Create.ascii(go_performance_mode)
|
54
|
+
Create.logo(go_fast)
|
File without changes
|
@@ -0,0 +1,204 @@
|
|
1
|
+
# assets.py β drop this next to utils/, purge.py, etc.
|
2
|
+
from haraka.art.ascii.assets import *
|
3
|
+
|
4
|
+
LANGUAGE_ASSETS = [
|
5
|
+
{
|
6
|
+
"language": "go",
|
7
|
+
"files": [
|
8
|
+
"Dockerfile",
|
9
|
+
"Makefile",
|
10
|
+
"Makefile.cpp",
|
11
|
+
"README.md",
|
12
|
+
"go.mod",
|
13
|
+
"skaffold.yaml",
|
14
|
+
"configs/dev.yaml",
|
15
|
+
"configs/prod.yaml",
|
16
|
+
"internal/config/config.go",
|
17
|
+
"internal/handler/echo.go",
|
18
|
+
"internal/handler/ping.go",
|
19
|
+
"internal/server/health.go",
|
20
|
+
"internal/server/server.go",
|
21
|
+
"pkg/proto/v1/ping.proto",
|
22
|
+
"pkg/proto/v1/service.proto",
|
23
|
+
# "cmd/{{ cookiecutter.project_slug }}/main.go",
|
24
|
+
"test/integration/echo_integration_test.go",
|
25
|
+
"test/integration/health_integration_test.go",
|
26
|
+
"test/integration/ping_integration_test.go",
|
27
|
+
"test/integration/testutil.go",
|
28
|
+
"test/unit/config/config_test.go",
|
29
|
+
"test/unit/handler/echo_test.go",
|
30
|
+
"test/unit/handler/ping_test.go",
|
31
|
+
"test/unit/server/health_test.go",
|
32
|
+
"test/unit/server/server_test.go",
|
33
|
+
"test/unit_test.go",
|
34
|
+
"test/package.go",
|
35
|
+
"runConfigurations/go/Golang.run.xml",
|
36
|
+
"chart/Chart.yaml",
|
37
|
+
"chart/templates/deployment.yaml",
|
38
|
+
"chart/templates/service.yaml",
|
39
|
+
"chart/templates/_helpers.tpl",
|
40
|
+
"chart/values.yaml",
|
41
|
+
"infra/terraform/main.tf",
|
42
|
+
"src/cpp/CMakeLists.txt",
|
43
|
+
"src/cpp/main.cc",
|
44
|
+
"tests/cpp/test_stub.cc"
|
45
|
+
],
|
46
|
+
"dirs": [
|
47
|
+
"cmd/",
|
48
|
+
"configs/",
|
49
|
+
"internal/",
|
50
|
+
"internal/config/",
|
51
|
+
"internal/handler/",
|
52
|
+
"internal/server/",
|
53
|
+
"pkg/",
|
54
|
+
"pkg/proto/",
|
55
|
+
"pkg/proto/v1/",
|
56
|
+
"test/",
|
57
|
+
"test/integration/",
|
58
|
+
"test/unit/",
|
59
|
+
"test/unit/config/",
|
60
|
+
"test/unit/handler/",
|
61
|
+
"test/unit/server/",
|
62
|
+
"runConfigurations/",
|
63
|
+
"runConfigurations/go/",
|
64
|
+
"chart/",
|
65
|
+
"chart/templates/",
|
66
|
+
"infra/",
|
67
|
+
"infra/terraform/",
|
68
|
+
"src/",
|
69
|
+
"src/cpp/",
|
70
|
+
"tests/",
|
71
|
+
"tests/cpp/"
|
72
|
+
]
|
73
|
+
},
|
74
|
+
{
|
75
|
+
"language": "python",
|
76
|
+
"files": [
|
77
|
+
"Dockerfile",
|
78
|
+
"Makefile",
|
79
|
+
"README.md",
|
80
|
+
"requirements.txt",
|
81
|
+
"pytest.ini",
|
82
|
+
"skaffold.yaml",
|
83
|
+
"src/app/__init__.py",
|
84
|
+
"src/app/main.py",
|
85
|
+
"src/app/core/config.py",
|
86
|
+
"src/app/services/health.py",
|
87
|
+
"src/app/schemas/health.py",
|
88
|
+
"src/app/api/v1/__init__.py",
|
89
|
+
"src/app/api/v1/routers/health.py",
|
90
|
+
"tests/__init__.py",
|
91
|
+
"tests/conftest.py",
|
92
|
+
"tests/integration/test_health_endpoint.py",
|
93
|
+
"tests/unit/api/v1/routers/test_health.py",
|
94
|
+
"tests/unit/schemas/test_health_schema.py"
|
95
|
+
],
|
96
|
+
"dirs": [
|
97
|
+
"src/",
|
98
|
+
"src/app/",
|
99
|
+
"src/app/core/",
|
100
|
+
"src/app/services/",
|
101
|
+
"src/app/schemas/",
|
102
|
+
"src/app/api/",
|
103
|
+
"src/app/api/v1/",
|
104
|
+
"src/app/api/v1/routers/",
|
105
|
+
"tests/",
|
106
|
+
"tests/integration/",
|
107
|
+
"tests/unit/",
|
108
|
+
"tests/unit/api/",
|
109
|
+
"tests/unit/api/v1/",
|
110
|
+
"tests/unit/api/v1/routers/",
|
111
|
+
"tests/unit/schemas/"
|
112
|
+
]
|
113
|
+
},
|
114
|
+
{
|
115
|
+
"language": "java",
|
116
|
+
"files": [
|
117
|
+
"Dockerfile",
|
118
|
+
"Makefile",
|
119
|
+
"README.md",
|
120
|
+
"pom.xml",
|
121
|
+
"skaffold.yaml",
|
122
|
+
"src/main/java/com/example/Application.java",
|
123
|
+
"src/main/java/com/example/config/OpenApiConfig.java",
|
124
|
+
"src/main/java/com/example/controller/HealthController.java",
|
125
|
+
"src/main/java/com/example/dto/HealthResponse.java",
|
126
|
+
"src/main/java/com/example/exception/GlobalExceptionHandler.java",
|
127
|
+
"src/main/java/com/example/service/HealthService.java",
|
128
|
+
"src/main/resources/application.yml",
|
129
|
+
"src/test/java/com/example/controller/HealthControllerTest.java",
|
130
|
+
"src/test/java/com/example/service/HealthServiceTest.java"
|
131
|
+
],
|
132
|
+
"dirs": [
|
133
|
+
"src/",
|
134
|
+
"src/main/",
|
135
|
+
"src/main/java/",
|
136
|
+
"src/main/java/com/",
|
137
|
+
"src/main/java/com/example/",
|
138
|
+
"src/main/java/com/example/config/",
|
139
|
+
"src/main/java/com/example/controller/",
|
140
|
+
"src/main/java/com/example/dto/",
|
141
|
+
"src/main/java/com/example/exception/",
|
142
|
+
"src/main/java/com/example/service/",
|
143
|
+
"src/main/resources/",
|
144
|
+
"src/test/",
|
145
|
+
"src/test/java/",
|
146
|
+
"src/test/java/com/",
|
147
|
+
"src/test/java/com/example/",
|
148
|
+
"src/test/java/com/example/controller/",
|
149
|
+
"src/test/java/com/example/service/"
|
150
|
+
]
|
151
|
+
}
|
152
|
+
]
|
153
|
+
|
154
|
+
# ------------------------------------------------------------------ #
|
155
|
+
# GLOBAL ASSETS (kept for every language) #
|
156
|
+
# ------------------------------------------------------------------ #
|
157
|
+
GLOBAL_ASSETS = {
|
158
|
+
"files": [
|
159
|
+
"Dockerfile",
|
160
|
+
"Makefile",
|
161
|
+
"README.md",
|
162
|
+
"skaffold.yaml",
|
163
|
+
"chart/Chart.yaml",
|
164
|
+
"chart/values.yaml",
|
165
|
+
"chart/templates/_helpers.tpl",
|
166
|
+
"chart/templates/deployment.yaml",
|
167
|
+
"chart/templates/service.yaml",
|
168
|
+
"infra/terraform/main.tf",
|
169
|
+
],
|
170
|
+
"dirs": [
|
171
|
+
"chart/",
|
172
|
+
"chart/templates/",
|
173
|
+
"infra/",
|
174
|
+
"infra/terraform/",
|
175
|
+
],
|
176
|
+
}
|
177
|
+
|
178
|
+
go_emoji_logo = [
|
179
|
+
emoji["go"]
|
180
|
+
]
|
181
|
+
go_performance_mode = [
|
182
|
+
goLang,
|
183
|
+
divider_xl,
|
184
|
+
performance_mode,
|
185
|
+
divider_l,
|
186
|
+
tools,
|
187
|
+
divider_s,
|
188
|
+
gRPC,
|
189
|
+
divider_mono,
|
190
|
+
protoC,
|
191
|
+
divider_mono,
|
192
|
+
autoMaxProcs,
|
193
|
+
divider_mono,
|
194
|
+
ants,
|
195
|
+
divider_mono,
|
196
|
+
zeroLog,
|
197
|
+
]
|
198
|
+
go_fast = [
|
199
|
+
goFast,
|
200
|
+
gRpc_ProtoBuf,
|
201
|
+
server,
|
202
|
+
by,
|
203
|
+
wjb_dev
|
204
|
+
]
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import subprocess, sys
|
2
|
+
from pathlib import Path
|
3
|
+
from typing import List, Optional
|
4
|
+
from haraka.utils import Logger
|
5
|
+
|
6
|
+
class CommandRunner:
|
7
|
+
|
8
|
+
"""Thin wrapper around subprocess.run with logging & graceful error-handling."""
|
9
|
+
|
10
|
+
def __init__(self, logger: Logger) -> None:
|
11
|
+
self._log = logger
|
12
|
+
|
13
|
+
def run(
|
14
|
+
self,
|
15
|
+
cmd: List[str],
|
16
|
+
*,
|
17
|
+
cwd: Optional[Path] = None,
|
18
|
+
check: bool = True,
|
19
|
+
) -> Optional[subprocess.CompletedProcess]:
|
20
|
+
cmd_str = " ".join(cmd)
|
21
|
+
self._log.info(f"Running: {cmd_str}")
|
22
|
+
try:
|
23
|
+
result = subprocess.run(
|
24
|
+
cmd,
|
25
|
+
cwd=str(cwd) if cwd else None,
|
26
|
+
check=check,
|
27
|
+
stdout=subprocess.PIPE,
|
28
|
+
stderr=subprocess.PIPE,
|
29
|
+
text=True,
|
30
|
+
)
|
31
|
+
if result.stdout:
|
32
|
+
self._log.info(f"stdout:\n{result.stdout.strip()}")
|
33
|
+
if result.stderr:
|
34
|
+
self._log.warn(f"stderr:\n{result.stderr.strip()}", file=sys.stderr)
|
35
|
+
return result
|
36
|
+
except subprocess.CalledProcessError as e:
|
37
|
+
self._log.error(f"command failed: ({cmd_str})", file=sys.stderr)
|
38
|
+
if e.stdout:
|
39
|
+
self._log.error(f"stdout:\n{e.stdout.strip()}", file=sys.stderr)
|
40
|
+
if e.stderr:
|
41
|
+
self._log.error(f"stderr:\n{e.stderr.strip()}", file=sys.stderr)
|
42
|
+
if check:
|
43
|
+
sys.exit(e.returncode)
|
44
|
+
return None
|
45
|
+
except FileNotFoundError:
|
46
|
+
self._log.error(f"command not found: {cmd[0]}", file=sys.stderr)
|
47
|
+
if check:
|
48
|
+
sys.exit(1)
|
49
|
+
return None
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import shutil
|
2
|
+
from pathlib import Path
|
3
|
+
from haraka.utils import Logger
|
4
|
+
|
5
|
+
class FileOps:
|
6
|
+
"""Filesystem helpers: remove files/dirs, print tree, nice dividers."""
|
7
|
+
def __init__(self, logger: Logger = Logger("βοΈοΈοΈοΈοΈοΈοΈοΈοΈοΈοΈοΈTestingβοΈ"), test_mode=False) -> None:
|
8
|
+
self.logger = logger
|
9
|
+
self.test_mode = test_mode
|
10
|
+
|
11
|
+
def _relpath(self, path: Path) -> str:
|
12
|
+
try:
|
13
|
+
return str(path.relative_to(Path.cwd()))
|
14
|
+
except ValueError:
|
15
|
+
return str(path) if self.test_mode else f"<non-project-path>: {path}"
|
16
|
+
|
17
|
+
def remove_file(self, path: Path) -> None:
|
18
|
+
try:
|
19
|
+
if path.is_file():
|
20
|
+
path.unlink()
|
21
|
+
self.logger.info(f"Removed file: {self._relpath(path)}")
|
22
|
+
elif path.is_dir():
|
23
|
+
shutil.rmtree(path, ignore_errors=True)
|
24
|
+
self.logger.info(f"Removed directory (expected file): {self._relpath(path)}")
|
25
|
+
except Exception as e:
|
26
|
+
self.logger.warn(f"Could not remove {self._relpath(path)}: {e}")
|
27
|
+
|
28
|
+
def remove_dir(self, path: Path) -> None:
|
29
|
+
if path.exists():
|
30
|
+
try:
|
31
|
+
shutil.rmtree(path, ignore_errors=True)
|
32
|
+
self.logger.info(f"Removed directory: {self._relpath(path)}")
|
33
|
+
except Exception as e:
|
34
|
+
self.logger.warn(f"Could not remove directory {self._relpath(path)}: {e}")
|
35
|
+
|
36
|
+
def print_tree(self, path: Path, prefix: str = "") -> None:
|
37
|
+
if not path.exists():
|
38
|
+
self.logger.warn(f"Path does not exist: {path}")
|
39
|
+
return
|
40
|
+
entries = sorted(path.iterdir(), key=lambda p: (p.is_file(), p.name.lower()))
|
41
|
+
for i, entry in enumerate(entries):
|
42
|
+
branch = "βββ " if i == len(entries) - 1 else "βββ "
|
43
|
+
print(prefix + branch + entry.name)
|
44
|
+
if entry.is_dir():
|
45
|
+
ext = " " if i == len(entries) - 1 else "β "
|
46
|
+
self.print_tree(entry, prefix + ext)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import shutil
|
2
|
+
import sys
|
3
|
+
from pathlib import Path
|
4
|
+
from .command import CommandRunner
|
5
|
+
import subprocess
|
6
|
+
from haraka.utils import Logger
|
7
|
+
|
8
|
+
class GitOps:
|
9
|
+
"""Git-related operations: init, commit, create remote, push."""
|
10
|
+
|
11
|
+
def __init__(self, runner: CommandRunner, logger: Logger) -> None:
|
12
|
+
self._r = runner
|
13
|
+
self._log = logger
|
14
|
+
|
15
|
+
# ------------- public API ----------------------------------------- #
|
16
|
+
def init_repo(self, project_dir: Path) -> None:
|
17
|
+
if not (project_dir / ".git").exists():
|
18
|
+
self._log.info("Initializing Git repositoryβ¦")
|
19
|
+
self._r.run(["git", "init"], cwd=project_dir)
|
20
|
+
self._r.run(["git", "branch", "-M", "main"], cwd=project_dir)
|
21
|
+
else:
|
22
|
+
self._log.warn(".git already exists; skipping git init.")
|
23
|
+
|
24
|
+
def stage_commit(self, project_dir: Path) -> None:
|
25
|
+
self._log.info("Staging filesβ¦")
|
26
|
+
self._r.run(["git", "add", "."], cwd=project_dir)
|
27
|
+
res = self._r.run(["git", "commit", "-m", "Initial commit"],
|
28
|
+
cwd=project_dir, check=False)
|
29
|
+
if not res or res.returncode:
|
30
|
+
self._log.error("'git commit' failed (maybe nothing to commit); continuingβ¦", file=sys.stderr)
|
31
|
+
|
32
|
+
def push_to_github(self, project_dir: Path, author: str,
|
33
|
+
slug: str, description: str) -> None:
|
34
|
+
if not self._has_gh():
|
35
|
+
return
|
36
|
+
if "origin" in self._current_remotes(project_dir):
|
37
|
+
self._log.warn("Remote 'origin' already exists; skipping create.")
|
38
|
+
return
|
39
|
+
repo = f"{author}/{slug}"
|
40
|
+
self._log.info(f"Creating GitHub repo {repo} & pushingβ¦")
|
41
|
+
self._r.run([
|
42
|
+
"gh", "repo", "create", repo,
|
43
|
+
"--public", "--description", description,
|
44
|
+
"--source", ".", "--remote", "origin", "--push", "--confirm"
|
45
|
+
], cwd=project_dir)
|
46
|
+
|
47
|
+
# ------------- internals ------------------------------------------ #
|
48
|
+
@staticmethod
|
49
|
+
def _current_remotes(project_dir: Path):
|
50
|
+
try:
|
51
|
+
res = subprocess.run(["git", "remote"], cwd=project_dir,
|
52
|
+
check=True, text=True,
|
53
|
+
stdout=subprocess.PIPE)
|
54
|
+
return [r.strip() for r in res.stdout.splitlines()]
|
55
|
+
except subprocess.CalledProcessError:
|
56
|
+
return []
|
57
|
+
|
58
|
+
@staticmethod
|
59
|
+
def _has_gh() -> bool:
|
60
|
+
return shutil.which("gh") is not None
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# haraka/post_gen/utils/purge.py
|
2
|
+
from pathlib import Path
|
3
|
+
from typing import Dict, Set
|
4
|
+
|
5
|
+
from .files import FileOps
|
6
|
+
from haraka.utils import Logger, divider
|
7
|
+
from haraka.post_gen.utils.assets import LANGUAGE_ASSETS, GLOBAL_ASSETS
|
8
|
+
|
9
|
+
|
10
|
+
class ResourcePurger:
|
11
|
+
"""Delete template artefacts not relevant to the selected language."""
|
12
|
+
|
13
|
+
def __init__(self, fops: FileOps, logger: Logger | None = None) -> None:
|
14
|
+
self._f = fops
|
15
|
+
self._log = logger or Logger("ResourcePurger")
|
16
|
+
|
17
|
+
# Build a quick lookup: language β {"files": set, "dirs": set}
|
18
|
+
self._index: Dict[str, Dict[str, Set[str]]] = {
|
19
|
+
spec["language"]: {
|
20
|
+
"files": set(spec["files"]),
|
21
|
+
# store directory names *without* trailing β/β
|
22
|
+
"dirs": {d.rstrip("/") for d in spec["dirs"]},
|
23
|
+
}
|
24
|
+
for spec in LANGUAGE_ASSETS
|
25
|
+
}
|
26
|
+
|
27
|
+
# ------------------------------------------------------------------ #
|
28
|
+
# public API #
|
29
|
+
# ------------------------------------------------------------------ #
|
30
|
+
def purge(self, language: str, project_dir: Path) -> None:
|
31
|
+
language = language.lower()
|
32
|
+
if language not in self._index:
|
33
|
+
self._log.warn(f"Unrecognised language '{language}'; skipping purge.")
|
34
|
+
return
|
35
|
+
|
36
|
+
self._log.info(f"Starting purge for language: {language}")
|
37
|
+
|
38
|
+
keep_files = self._index[language]["files"] | set(GLOBAL_ASSETS["files"])
|
39
|
+
keep_dirs = self._index[language]["dirs"] | {
|
40
|
+
d.rstrip("/") for d in GLOBAL_ASSETS["dirs"]
|
41
|
+
}
|
42
|
+
|
43
|
+
self._log.info(f"Keeping {len(keep_files)} files & {len(keep_dirs)} dirs")
|
44
|
+
|
45
|
+
self._purge_unrelated(project_dir, keep_files, keep_dirs)
|
46
|
+
|
47
|
+
divider("Project tree after purgeβ¦")
|
48
|
+
self._f.print_tree(project_dir)
|
49
|
+
|
50
|
+
# ------------------------------------------------------------------ #
|
51
|
+
# internals #
|
52
|
+
# ------------------------------------------------------------------ #
|
53
|
+
def _purge_unrelated(
|
54
|
+
self,
|
55
|
+
root: Path,
|
56
|
+
keep_files: Set[str],
|
57
|
+
keep_dirs: Set[str],
|
58
|
+
) -> None:
|
59
|
+
for path in root.rglob("*"):
|
60
|
+
rel = path.relative_to(root).as_posix()
|
61
|
+
|
62
|
+
inside_kept_dir = any(rel.startswith(d + "/") for d in keep_dirs)
|
63
|
+
|
64
|
+
if rel in keep_files or rel in keep_dirs or inside_kept_dir:
|
65
|
+
continue # safe
|
66
|
+
|
67
|
+
if path.is_dir():
|
68
|
+
self._f.remove_dir(path)
|
69
|
+
else:
|
70
|
+
self._f.remove_file(path)
|
haraka/utils/__init__.py
ADDED
File without changes
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
def _term_width() -> int:
|
4
|
+
try:
|
5
|
+
return os.get_terminal_size().columns
|
6
|
+
except OSError:
|
7
|
+
return 60
|
8
|
+
|
9
|
+
# -------- pretty printing ------------------------------------------ #
|
10
|
+
def divider(title: str, *, char: str = "=") -> None:
|
11
|
+
width = _term_width()
|
12
|
+
print("\n" + char * width)
|
13
|
+
print(title)
|
14
|
+
print(char * width + "\n")
|
File without changes
|
@@ -0,0 +1,28 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
import sys
|
3
|
+
from typing import TextIO
|
4
|
+
|
5
|
+
|
6
|
+
class Logger:
|
7
|
+
def __init__(self, label: str = ""):
|
8
|
+
self.label = label
|
9
|
+
|
10
|
+
def start_logger(self) -> Logger:
|
11
|
+
label = Logger.get_label(self.label)
|
12
|
+
return Logger(label)
|
13
|
+
|
14
|
+
def info(self, msg: str) -> None:
|
15
|
+
print(f"{self.label} INFO: {msg}")
|
16
|
+
|
17
|
+
def warn(self, msg: str, file: TextIO = sys.stderr) -> None:
|
18
|
+
print(f"{self.label} WARNING: {msg}", file=file)
|
19
|
+
|
20
|
+
def error(self, msg: str, file: TextIO = sys.stderr) -> None:
|
21
|
+
print(f"{self.label} ERROR: {msg}", file=file)
|
22
|
+
|
23
|
+
@staticmethod
|
24
|
+
def get_label(language: str) -> str:
|
25
|
+
if language == "go":
|
26
|
+
return f"[π₯Go Fast: post_gen]"
|
27
|
+
return f"[π₯post_gen ({language})]"
|
28
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: haraka
|
3
|
+
Version: 0.2.5
|
4
|
+
Summary: Reusable post-generation helper for Cookiecutter micro-service templates
|
5
|
+
Author-email: Will Burks <will@example.com>
|
6
|
+
License: MIT
|
7
|
+
Project-URL: Homepage, https://github.com/wjb-dev/comet-postgen
|
8
|
+
Project-URL: Source, https://github.com/wjb-dev/comet-postgen
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
11
|
+
Classifier: Intended Audience :: Developers
|
12
|
+
Classifier: Topic :: Software Development :: Build Tools
|
13
|
+
Requires-Python: >=3.9
|
14
|
+
Description-Content-Type: text/markdown
|
@@ -0,0 +1,28 @@
|
|
1
|
+
haraka/__init__.py,sha256=oQxsY6uhvvb8bUdYvbP6oWo48gfzJLunsYTVmFFSKBs,176
|
2
|
+
haraka/art/__init__.py,sha256=-b1KHQiLkaI2sXaHS05XDaE27tZfXvVLitILjJfSiKs,112
|
3
|
+
haraka/art/create.py,sha256=D2VPJtuwI0Ed7CcreHRHhxSN1VzV7PQfC1q-NW8l0DY,631
|
4
|
+
haraka/art/ascii/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
haraka/art/ascii/assets.py,sha256=1WUxFQ0xlzaScVe6hXh6gHKggtLhYc3gfHi9CoW9Otc,9159
|
6
|
+
haraka/art/ascii/frame/__init__.py,sha256=9Y1qWC-82ZK_kLhRq749hh_3tXb0mMaPkHq70jtElTc,156
|
7
|
+
haraka/art/ascii/frame/border.py,sha256=n7qaLxzzBmf8ewatbe5gN97DO4afZM67bBjpU1OqgAM,1318
|
8
|
+
haraka/art/ascii/frame/framer.py,sha256=s_-lsb-hGhlH_73q5iTtk8KHW0MSeSHSAvNFVmL1c9A,3951
|
9
|
+
haraka/art/ascii/frame/width_utils.py,sha256=in4AV3gTBBXUX6N01j67Icu9vsHFomybBN8rpL3sQ5s,810
|
10
|
+
haraka/post_gen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
+
haraka/post_gen/runner.py,sha256=nKVprtGZzVJBhRwU4vDV6op2d63RQ30BEX6XinuSdIY,1813
|
12
|
+
haraka/post_gen/config/__init__.py,sha256=-_XkJ_Dni28yJCMfIceQSiH1wa_hHsZMoBTyvR9Ikbc,62
|
13
|
+
haraka/post_gen/config/config.py,sha256=VpRgp_-dU1sJd3Jow3MAOeerqElzBcHdkSqvgd1bkwk,234
|
14
|
+
haraka/post_gen/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
|
+
haraka/post_gen/utils/assets.py,sha256=UARi1iDczVHoNGm5FpKkSXCk-yvnzyMMtSJM1SxMRSA,6157
|
16
|
+
haraka/post_gen/utils/command.py,sha256=5yxPSQmQpzAyPNoLtzxaUz1VWgPnTfD7XlkBUu5rIeI,1672
|
17
|
+
haraka/post_gen/utils/files.py,sha256=1hPHn_nYI5A2JKJqxmNFK5fpo9DNPcGR4K7qCPOO5GE,1993
|
18
|
+
haraka/post_gen/utils/gitops.py,sha256=hRnztg_5yW3L_bdh05gcgGQ25wwjSTn8pX1sja-m91s,2434
|
19
|
+
haraka/post_gen/utils/purge.py,sha256=9EQg-CdFVnjEo-KY9_Au_emicpZId7z2-QyWFPLty-M,2633
|
20
|
+
haraka/utils/__init__.py,sha256=dqjKz10MTfH6fFl68cu_giWYYZ41HAUDg_0-OwC1qjE,246
|
21
|
+
haraka/utils/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
|
+
haraka/utils/common/utils.py,sha256=kMnMXe_hcxGkD0MKGmR1lIwsRND7BaFPRbGN4PwonfM,360
|
23
|
+
haraka/utils/logging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
|
+
haraka/utils/logging/log_util.py,sha256=rl-VnSPns84MPDp7SwArtrO4oPHUPUiRNdkp0NBvxsY,778
|
25
|
+
haraka-0.2.5.dist-info/METADATA,sha256=hgLAOgD2_WhGfof6xrY1U5k5u0GuIvnZfODD9g6uc_c,578
|
26
|
+
haraka-0.2.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
27
|
+
haraka-0.2.5.dist-info/top_level.txt,sha256=1khpwypLKWoklVd_CgFiwAfcctVSXRoRPc3BI9lyIXo,7
|
28
|
+
haraka-0.2.5.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
haraka
|