Skip to content

Commit cabf5eb

Browse files
committed
Merge remote-tracking branch 'origin/main' into feature/v3-architecture
2 parents a6679d7 + 3ce5ad1 commit cabf5eb

2 files changed

Lines changed: 78 additions & 14 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.idea
22
.vscode
33
*.pyc
4+
*.egg-info/
45
docs/
56
site/
6-

src/viur_cli/scriptor/cli.py

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import requests
55
import os
66
import hashlib
7+
import difflib
78
import asyncio
89
import sys
910
import glob
@@ -34,7 +35,7 @@ def script():
3435

3536

3637
@script.command()
37-
@click.option('--url', default=None, help='Set the url')
38+
@click.option('--url', default=None, help='Set the server url')
3839
@click.option('--username', default=None, help='Set the username')
3940
@click.option('--working_dir', default=None, help='Set the working directory where scripts are stored to')
4041
def configure(url: str, username: str, working_dir: str):
@@ -43,15 +44,32 @@ def configure(url: str, username: str, working_dir: str):
4344
Only flags that are passed are written; the rest of the
4445
`viur_scriptor_config.json` keeps its previous values.
4546
"""
47+
if not any([url, username, working_dir]):
48+
click.echo("No parameters provided. Use one or more of the following options:")
49+
click.echo(" --url Set the server URL")
50+
click.echo(" --username Set the username")
51+
click.echo(" --working_dir Set the working directory where scripts are stored to")
52+
return
53+
54+
changed = []
4655

4756
if url:
4857
scriptor_config["base_url"] = url
58+
changed.append(f"url = {url}")
4959

5060
if username:
5161
scriptor_config["username"] = username
62+
changed.append(f"username = {username}")
5263

5364
if working_dir:
5465
scriptor_config["working_dir"] = working_dir.replace("\\", "/")
66+
changed.append(f"working_dir = {working_dir}")
67+
68+
click.echo("Configuration updated:")
69+
for entry in changed:
70+
click.echo(f" {entry}")
71+
72+
scriptor_config.save()
5573

5674

5775
@script.command()
@@ -115,7 +133,8 @@ def check_session(ctx: click.Context):
115133
get_modules()
116134

117135
@script.command()
118-
@click.option('--force', default=False, help='Force replace files from server in local working directory')
136+
@click.option('--force', default=False, is_flag=True,
137+
help='Overwrite local files without asking for confirmation')
119138
@click.pass_context
120139
def pull(ctx: click.Context, force: bool):
121140
"""Download all server-side Scriptor scripts into the local working_dir.
@@ -131,36 +150,74 @@ async def main():
131150
tree = await modules.get_module("script")
132151
working_dir = scriptor_config.get("working_dir")
133152

153+
stats = {"new": 0, "updated": 0, "skipped": 0, "unchanged": 0, "dirs": 0}
154+
134155
async def process_entry(entry: dict, is_node: bool):
135156
_path = os.path.join(working_dir, entry["path"].lstrip("/"))
136157

137158
if is_node:
138159
if not os.path.exists(_path):
160+
click.echo(click.style(f" mkdir {entry['path']}", fg="blue"))
139161
os.makedirs(_path)
162+
stats["dirs"] += 1
140163
else:
164+
click.echo(f" check {entry['path']}", nl=False)
165+
141166
def create_file():
142167
with open(_path, "a+") as f:
143168
f.write(entry["script"])
144169

145-
click.echo(f"Pull {_path}")
146-
147170
if os.path.exists(_path):
148171
if force:
172+
with open(_path, "r") as f:
173+
changed = f.read().splitlines() != entry["script"].splitlines()
149174
os.remove(_path)
150175
create_file()
176+
if changed:
177+
click.echo(click.style(" [updated]", fg="yellow"))
178+
stats["updated"] += 1
179+
else:
180+
click.echo(click.style(" [ok]", fg="green"))
181+
stats["unchanged"] += 1
151182
else:
152183
with open(_path, "r") as f:
153-
if hashlib.sha256(entry["script"].encode()).digest() \
154-
!= hashlib.sha256(f.read().encode()).digest():
155-
try:
156-
if click.confirm(f"There is a difference with {entry['path']}. Overwrite?"):
157-
os.remove(_path)
158-
create_file()
159-
except click.exceptions.Abort:
160-
click.echo("\nSkipping...")
161-
184+
local_content = f.read()
185+
remote_content = entry["script"]
186+
diff = list(difflib.unified_diff(
187+
remote_content.splitlines(),
188+
local_content.splitlines(),
189+
fromfile=f"server/{entry['path'].lstrip('/')}",
190+
tofile=f"local/{entry['path'].lstrip('/')}",
191+
lineterm="",
192+
))
193+
if diff:
194+
click.echo(click.style(" [diff]", fg="yellow"))
195+
for line in diff:
196+
if line.startswith("+++") or line.startswith("---"):
197+
click.echo(click.style(line, bold=True))
198+
elif line.startswith("@@"):
199+
click.echo(click.style(line, fg="cyan"))
200+
elif line.startswith("+"):
201+
click.echo(click.style(line, fg="green"))
202+
elif line.startswith("-"):
203+
click.echo(click.style(line, fg="red"))
204+
else:
205+
click.echo(line)
206+
if click.confirm(f"Overwrite local {entry['path']} with remote version?"):
207+
os.remove(_path)
208+
create_file()
209+
stats["updated"] += 1
210+
else:
211+
stats["skipped"] += 1
212+
else:
213+
click.echo(click.style(" [ok]", fg="green"))
214+
stats["unchanged"] += 1
162215
else:
216+
click.echo(click.style(" [new]", fg="green"))
163217
create_file()
218+
stats["new"] += 1
219+
220+
click.echo("Fetching scripts from server...")
164221

165222
# Process nodes first
166223
async for node in tree.list(skel_type="node"):
@@ -170,6 +227,13 @@ def create_file():
170227
async for leaf in tree.list(skel_type="leaf"):
171228
await process_entry(leaf, False)
172229

230+
click.echo("")
231+
click.echo(click.style("Summary:", bold=True))
232+
click.echo(f" new: {stats['new']}")
233+
click.echo(f" updated: {stats['updated']}")
234+
click.echo(f" skipped: {stats['skipped']}")
235+
click.echo(f" unchanged: {stats['unchanged']}")
236+
173237
asyncio.run(main())
174238

175239

0 commit comments

Comments
 (0)