Skip to content

Commit 8b57202

Browse files
committed
refactor build: mv userver-create-service -> userver-create-service.py
commit_hash:b337f2a385326758f5eac76fa529172371ea2f73
1 parent 2987c76 commit 8b57202

File tree

8 files changed

+158
-158
lines changed

8 files changed

+158
-158
lines changed

.mapping.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4596,6 +4596,7 @@
45964596
"scripts/uctl/uctl.bash_completion.sh":"taxi/uservices/userver/scripts/uctl/uctl.bash_completion.sh",
45974597
"scripts/uctl/uctl.py":"taxi/uservices/userver/scripts/uctl/uctl.py",
45984598
"scripts/userver-create-service":"taxi/uservices/userver/scripts/userver-create-service",
4599+
"scripts/userver-create-service.py":"taxi/uservices/userver/scripts/userver-create-service.py",
45994600
"service_template/.clang-format":"taxi/uservices/userver/service_template/.clang-format",
46004601
"service_template/.devcontainer/README.md":"taxi/uservices/userver/service_template/.devcontainer/README.md",
46014602
"service_template/.devcontainer/devcontainer.json":"taxi/uservices/userver/service_template/.devcontainer/devcontainer.json",

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ endif()
334334
if(USERVER_FEATURE_CORE)
335335
_userver_directory_install(
336336
COMPONENT core
337-
PROGRAMS "${USERVER_ROOT_DIR}/scripts/userver-create-service"
337+
PROGRAMS "${USERVER_ROOT_DIR}/scripts/userver-create-service.py"
338338
DESTINATION ${CMAKE_INSTALL_BINDIR}/
339339
RENAME userver-create-service
340340
)

scripts/create-service-test-helper

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ CMAKE_OPTS=$1
1010
shift
1111

1212
rm -rf "${BINARY_DIR}/new-service"
13-
"${USERVER}/scripts/userver-create-service" $* "${BINARY_DIR}/new-service"
13+
"${USERVER}/scripts/userver-create-service.py" $* "${BINARY_DIR}/new-service"
1414
cd "${BINARY_DIR}/new-service"
1515
mkdir third_party
1616
ln -s "${USERVER}" third_party/userver

scripts/docs/en/userver/build/build.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,13 @@ userver-create-service [--grpc] [--mongo] [--postgresql] myservice
103103
* service name will be the last segment of the path;
104104
* without feature flags, the service only has some stubs for HTTP handlers.
105105

106-
If you use @ref devcontainers "Dev Containers", or if you use CPM to download userver,
107-
run this script as the `userver-create-service` command:
106+
If you use @ref devcontainers "Dev Containers", or if you @ref userver_cpm "use CPM to download userver",
107+
run this script to get `userver-create-service` command:
108108

109109
* Linux, macOS, BSD: @ref service-template/userver-create-service.sh
110110
* Windows: @ref service-template/userver-create-service.bat
111111

112-
In the command, replace `vMAJOR.MINOR` with the actual userver version, or use `develop` to get bleeding-edge features
112+
In the script, replace `vMAJOR.MINOR` with the actual userver version, or use `develop` to get bleeding-edge features
113113
at your own risk.
114114

115115
If instead of installing userver you are planning to build userver as a subdirectory,
Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
1-
@echo off
2-
setlocal
3-
41
set "REPO_URL=https://github.com/userver-framework/userver.git"
52
set "BRANCH=vMAJOR.MINOR"
63
set "WORKDIR=%TEMP%\userver-create-service\%BRANCH%"
7-
84
if not exist "%WORKDIR%\" (
95
mkdir "%WORKDIR%"
106
git clone -q --depth 1 --branch "%BRANCH%" "%REPO_URL%" "%WORKDIR%"
117
)
12-
13-
py -3 "%WORKDIR%\scripts\userver-create-service" %*
8+
doskey userver-create-service=py -3 "%WORKDIR%\scripts\userver-create-service.py" $*
Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
REPO_URL="https://github.com/userver-framework/userver.git"
2-
BRANCH="vMAJOR.MINOR"
3-
WORKDIR="/tmp/userver-create-service/$BRANCH"
4-
if [ ! -d "$WORKDIR" ]; then
5-
mkdir -p "$WORKDIR"
6-
git clone -q --depth 1 --branch "$BRANCH" "$REPO_URL" "$WORKDIR"
7-
fi
8-
"$WORKDIR/scripts/userver-create-service" "$@"
1+
userver-create-service() {
2+
REPO_URL="https://github.com/userver-framework/userver.git"
3+
BRANCH="vMAJOR.MINOR"
4+
WORKDIR="/tmp/userver-create-service/$BRANCH"
5+
if [ ! -d "$WORKDIR" ]; then
6+
mkdir -p "$WORKDIR"
7+
git clone -q --depth 1 --branch "$BRANCH" "$REPO_URL" "$WORKDIR"
8+
fi
9+
"$WORKDIR/scripts/userver-create-service" "$@"
10+
}

scripts/userver-create-service

Lines changed: 2 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,139 +1,2 @@
1-
#!/usr/bin/python3
2-
3-
import argparse
4-
import os
5-
import pathlib
6-
import re
7-
import subprocess
8-
import sys
9-
10-
11-
BINDIR = pathlib.Path(__file__).parent
12-
FEATURES = [
13-
'mongo',
14-
'postgresql',
15-
'grpc',
16-
]
17-
TEMPLATE_ON_REGEX = re.compile(r'.* ([a-z]+) template on.*')
18-
TEMPLATE_CURRENT_REGEX = re.compile(r'(.*) (//|#) ([a-z]+) template current$')
19-
20-
21-
def is_system_installed() -> bool:
22-
return BINDIR.name == 'bin'
23-
24-
25-
def template_path() -> pathlib.Path:
26-
if is_system_installed():
27-
return BINDIR / '..' / 'share' / 'userver' / 'service_template'
28-
return BINDIR / '..' / 'service_template'
29-
30-
31-
def version_file_path() -> pathlib.Path:
32-
if is_system_installed():
33-
return BINDIR / '..' / 'share' / 'userver' / 'version.txt'
34-
return BINDIR / '..' / 'version.txt'
35-
36-
37-
def get_userver_version() -> str:
38-
version_path = version_file_path()
39-
return version_path.read_text().strip()
40-
41-
42-
def get_devcontainer_version(userver_version: str) -> str:
43-
if userver_version.endswith('-rc'):
44-
return 'latest'
45-
return f'v{userver_version}'
46-
47-
48-
def patch_devcontainer_version(service_path: pathlib.Path) -> None:
49-
devcontainer_path = service_path / '.devcontainer' / 'devcontainer.json'
50-
51-
userver_version = get_userver_version()
52-
devcontainer_version = get_devcontainer_version(userver_version)
53-
54-
content = devcontainer_path.read_text()
55-
content = re.sub(r'"(ghcr\.io/[^"]+)"', rf'"\1:{devcontainer_version}"', content)
56-
devcontainer_path.write_text(content)
57-
58-
59-
def parse_args():
60-
parser = argparse.ArgumentParser(
61-
description='Create new C++ userver-based service')
62-
for feature in FEATURES:
63-
parser.add_argument(f'--{feature}', action='store_true')
64-
parser.add_argument('service_path', type=pathlib.Path)
65-
return parser.parse_args()
66-
67-
68-
def service_name(service_path: pathlib.Path) -> str:
69-
return service_path.resolve().name.replace('-', '_')
70-
71-
72-
def handle_file(src: pathlib.Path, dst: pathlib.Path, args) -> bool:
73-
orig_text = src.read_text()
74-
text = []
75-
skip = False
76-
for line in orig_text.splitlines():
77-
line = line.replace('service_template', service_name(args.service_path))
78-
match_on = TEMPLATE_ON_REGEX.match(line)
79-
match_current = TEMPLATE_CURRENT_REGEX.match(line)
80-
if match_on:
81-
feature = match_on.group(1)
82-
assert feature in FEATURES, f'{feature} not in {FEATURES}'
83-
skip = not getattr(args, feature)
84-
elif 'template off' in line:
85-
skip = False
86-
elif match_current:
87-
feature = match_current.group(3)
88-
assert feature in FEATURES, f'{feature} not in {FEATURES}'
89-
if getattr(args, feature):
90-
text.append(match_current.group(1))
91-
else:
92-
if not skip:
93-
text.append(line)
94-
if text:
95-
dst.write_text('\n'.join(text))
96-
dst.chmod(src.lstat().st_mode)
97-
return True
98-
return False
99-
100-
101-
def copy_tree(src: pathlib.Path, dst: pathlib.Path, args) -> None:
102-
for root, _, files in os.walk(src):
103-
dst_root = dst / pathlib.Path(root).relative_to(src)
104-
dst_root.mkdir(parents=True, exist_ok=True)
105-
dst_root_is_empty = True
106-
107-
for file in files:
108-
src_filepath = pathlib.Path(root) / file
109-
dst_filepath = dst_root / file
110-
if handle_file(src_filepath, dst_filepath, args):
111-
dst_root_is_empty = False
112-
113-
if dst_root_is_empty:
114-
dst_root.rmdir()
115-
116-
117-
def run_ruff(src: pathlib.Path) -> None:
118-
try:
119-
subprocess.check_call(['ruff', 'format', str(src)])
120-
except BaseException as exc:
121-
print(f'Warning: Failed to run ruff ({exc}), skipping.', file=sys.stderr)
122-
123-
124-
def check_dst_non_existing(service_path: pathlib.Path):
125-
if service_path.exists():
126-
print(f'Error: {service_path} directory already exists.', file=sys.stderr)
127-
sys.exit(1)
128-
129-
130-
def main() -> None:
131-
args = parse_args()
132-
check_dst_non_existing(args.service_path)
133-
copy_tree(template_path(), args.service_path, args)
134-
patch_devcontainer_version(args.service_path)
135-
run_ruff(args.service_path)
136-
137-
138-
if __name__ == '__main__':
139-
main()
1+
#!/bin/sh
2+
./userver-create-service.py "$@"

scripts/userver-create-service.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#!/usr/bin/python3
2+
3+
import argparse
4+
import os
5+
import pathlib
6+
import re
7+
import subprocess
8+
import sys
9+
10+
11+
BINDIR = pathlib.Path(__file__).parent
12+
FEATURES = [
13+
'mongo',
14+
'postgresql',
15+
'grpc',
16+
]
17+
TEMPLATE_ON_REGEX = re.compile(r'.* ([a-z]+) template on.*')
18+
TEMPLATE_CURRENT_REGEX = re.compile(r'(.*) (//|#) ([a-z]+) template current$')
19+
20+
21+
def is_system_installed() -> bool:
22+
return BINDIR.name == 'bin'
23+
24+
25+
def template_path() -> pathlib.Path:
26+
if is_system_installed():
27+
return BINDIR / '..' / 'share' / 'userver' / 'service_template'
28+
return BINDIR / '..' / 'service_template'
29+
30+
31+
def version_file_path() -> pathlib.Path:
32+
if is_system_installed():
33+
return BINDIR / '..' / 'share' / 'userver' / 'version.txt'
34+
return BINDIR / '..' / 'version.txt'
35+
36+
37+
def get_userver_version() -> str:
38+
version_path = version_file_path()
39+
return version_path.read_text().strip()
40+
41+
42+
def get_devcontainer_version(userver_version: str) -> str:
43+
if userver_version.endswith('-rc'):
44+
return 'latest'
45+
return f'v{userver_version}'
46+
47+
48+
def patch_devcontainer_version(service_path: pathlib.Path) -> None:
49+
devcontainer_path = service_path / '.devcontainer' / 'devcontainer.json'
50+
51+
userver_version = get_userver_version()
52+
devcontainer_version = get_devcontainer_version(userver_version)
53+
54+
content = devcontainer_path.read_text()
55+
content = re.sub(r'"(ghcr\.io/[^"]+)"', rf'"\1:{devcontainer_version}"', content)
56+
devcontainer_path.write_text(content)
57+
58+
59+
def parse_args():
60+
parser = argparse.ArgumentParser(
61+
description='Create new C++ userver-based service')
62+
for feature in FEATURES:
63+
parser.add_argument(f'--{feature}', action='store_true')
64+
parser.add_argument('service_path', type=pathlib.Path)
65+
return parser.parse_args()
66+
67+
68+
def service_name(service_path: pathlib.Path) -> str:
69+
return service_path.resolve().name.replace('-', '_')
70+
71+
72+
def handle_file(src: pathlib.Path, dst: pathlib.Path, args) -> bool:
73+
orig_text = src.read_text()
74+
text = []
75+
skip = False
76+
for line in orig_text.splitlines():
77+
line = line.replace('service_template', service_name(args.service_path))
78+
match_on = TEMPLATE_ON_REGEX.match(line)
79+
match_current = TEMPLATE_CURRENT_REGEX.match(line)
80+
if match_on:
81+
feature = match_on.group(1)
82+
assert feature in FEATURES, f'{feature} not in {FEATURES}'
83+
skip = not getattr(args, feature)
84+
elif 'template off' in line:
85+
skip = False
86+
elif match_current:
87+
feature = match_current.group(3)
88+
assert feature in FEATURES, f'{feature} not in {FEATURES}'
89+
if getattr(args, feature):
90+
text.append(match_current.group(1))
91+
else:
92+
if not skip:
93+
text.append(line)
94+
if text:
95+
dst.write_text('\n'.join(text))
96+
dst.chmod(src.lstat().st_mode)
97+
return True
98+
return False
99+
100+
101+
def copy_tree(src: pathlib.Path, dst: pathlib.Path, args) -> None:
102+
for root, _, files in os.walk(src):
103+
dst_root = dst / pathlib.Path(root).relative_to(src)
104+
dst_root.mkdir(parents=True, exist_ok=True)
105+
dst_root_is_empty = True
106+
107+
for file in files:
108+
src_filepath = pathlib.Path(root) / file
109+
dst_filepath = dst_root / file
110+
if handle_file(src_filepath, dst_filepath, args):
111+
dst_root_is_empty = False
112+
113+
if dst_root_is_empty:
114+
dst_root.rmdir()
115+
116+
117+
def run_ruff(src: pathlib.Path) -> None:
118+
try:
119+
subprocess.check_call(['ruff', 'format', str(src)])
120+
except BaseException as exc:
121+
print(f'Warning: Failed to run ruff ({exc}), skipping.', file=sys.stderr)
122+
123+
124+
def check_dst_non_existing(service_path: pathlib.Path):
125+
if service_path.exists():
126+
print(f'Error: {service_path} directory already exists.', file=sys.stderr)
127+
sys.exit(1)
128+
129+
130+
def main() -> None:
131+
args = parse_args()
132+
check_dst_non_existing(args.service_path)
133+
copy_tree(template_path(), args.service_path, args)
134+
patch_devcontainer_version(args.service_path)
135+
run_ruff(args.service_path)
136+
137+
138+
if __name__ == '__main__':
139+
main()

0 commit comments

Comments
 (0)