-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix reinstall not detecting changed permissions by itself #6658
base: 8.4.x
Are you sure you want to change the base?
Changes from all commits
fc822f3
51d8919
b09170b
f8e206e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Fixed `cylc reinstall` not picking up file permissions changes. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -180,9 +180,14 @@ def get_includes_to_rsync(rsync_includes=None): | |
DEFAULT_RSYNC_OPTS = [ | ||
'-a', | ||
'--checksum', | ||
'--out-format=%o %n%L', | ||
'--out-format=%i %o %n%L', # see comment below | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want to include
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The rsync output isn't included in the reinstall logs. The only thing we do with the rsync output is print it to stdout in the dry-run case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it is, install a workflow, make changes, then check There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah ok - it's only included in the |
||
'--no-t' | ||
] | ||
# %o: the operation (send or del.) | ||
# %i: itemized changes (needed for rsync to report files with | ||
# changed permissions) | ||
# %n: filename | ||
# %L: "-> symlink_target" if applicable | ||
|
||
DEFAULT_INCLUDES = [ | ||
'/ana/***', # Rose ana analysis modules | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,33 +68,43 @@ | |
"cylc install" even if present in the source directory. | ||
""" | ||
|
||
from functools import partial | ||
from pathlib import Path | ||
import re | ||
import sys | ||
from typing import Optional, TYPE_CHECKING, List, Callable | ||
from functools import partial | ||
from typing import ( | ||
TYPE_CHECKING, | ||
Callable, | ||
List, | ||
Optional, | ||
) | ||
|
||
from ansimarkup import parse as cparse | ||
|
||
from cylc.flow.exceptions import ( | ||
ServiceFileError, | ||
WorkflowFilesError, | ||
) | ||
from cylc.flow.install import ( | ||
reinstall_workflow, | ||
) | ||
import cylc.flow.flags | ||
from cylc.flow.install import reinstall_workflow | ||
from cylc.flow.network.multi import call_multi | ||
from cylc.flow.option_parsers import ( | ||
ID_MULTI_ARG_DOC, | ||
CylcOptionParser as COP, | ||
OptionSettings, | ||
ID_MULTI_ARG_DOC | ||
) | ||
from cylc.flow.pathutil import get_workflow_run_dir | ||
from cylc.flow.plugins import run_plugins_async | ||
from cylc.flow.terminal import ( | ||
DIM, | ||
cli_function, | ||
is_terminal, | ||
) | ||
from cylc.flow.workflow_files import ( | ||
get_workflow_source_dir, | ||
load_contact_file, | ||
) | ||
from cylc.flow.terminal import cli_function, DIM, is_terminal | ||
|
||
|
||
if TYPE_CHECKING: | ||
from optparse import Values | ||
|
@@ -269,9 +279,8 @@ async def reinstall( | |
update anything, else returns True. | ||
|
||
""" | ||
# run pre_configure plugins | ||
if not dry_run: | ||
# don't run plugins in dry-mode | ||
# run pre_configure plugins | ||
async for _entry_point, _plugin_result in run_plugins_async( | ||
'cylc.pre_configure', | ||
srcdir=src_dir, | ||
|
@@ -287,18 +296,17 @@ async def reinstall( | |
dry_run=dry_run, | ||
) | ||
|
||
# display changes | ||
if dry_run: | ||
if not stdout or stdout == 'send ./': | ||
# no rsync output == no changes => exit | ||
# display changes | ||
changes = format_reinstall_output(stdout) | ||
if not changes: | ||
return False | ||
|
||
# display rsync output | ||
write('\n'.join(format_rsync_out(stdout)), file=sys.stderr) | ||
write('\n'.join(changes), file=sys.stdout) | ||
|
||
# run post_install plugins | ||
if not dry_run: | ||
# don't run plugins in dry-mode | ||
# run post_install plugins | ||
async for _entry_point, _plugin_result in run_plugins_async( | ||
'cylc.post_install', | ||
srcdir=src_dir, | ||
|
@@ -311,15 +319,15 @@ async def reinstall( | |
return True | ||
|
||
|
||
def format_rsync_out(out: str) -> List[str]: | ||
def format_reinstall_output(out: str) -> List[str]: | ||
r"""Format rsync stdout for presenting to users. | ||
|
||
Note: Output formats of different rsync implementations may differ so keep | ||
this code simple and robust. | ||
|
||
Example: | ||
>>> format_rsync_out( | ||
... 'send foo\ndel. bar\nbaz' | ||
>>> format_reinstall_output( | ||
... '>f+++++++++ send foo\n*deleting del. bar\nbaz' | ||
... '\ncannot delete non-empty directory: opt' | ||
... ) == [ | ||
... cparse('<green>send foo</green>'), | ||
|
@@ -331,20 +339,23 @@ def format_rsync_out(out: str) -> List[str]: | |
""" | ||
lines = [] | ||
for line in out.splitlines(): | ||
if line[0:4] == 'send': | ||
# file added or updated | ||
lines.append(cparse(f'<green>{line}</green>')) | ||
elif line[0:4] == 'del.': | ||
# file deleted | ||
lines.append(cparse(f'<red>{line}</red>')) | ||
elif line == 'cannot delete non-empty directory: opt': | ||
# These "cannot delete non-empty directory" messages can arise | ||
# as a result of excluding files within sub-directories. | ||
# This opt dir message is likely to occur when a rose-suit.conf | ||
if not line or line.startswith('cannot delete non-empty directory:'): | ||
# This can arise as a result of deleting a subdir when we are | ||
# excluding files within the subdir. | ||
# This is likely to occur for the opt dir when a rose-suite.conf | ||
# file is present. | ||
# Skip this line as nothing will happen to this dir. | ||
continue | ||
match = re.match(r'^(.{11}) (send|del\.) (.*)$', line) | ||
if match: | ||
summary, operation, file = match.groups() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [should not block/nice to have] |
||
color = 'green' if operation == 'send' else 'red' | ||
formatted_line = f"<{color}>{operation} {file}</{color}>" | ||
if cylc.flow.flags.verbosity > 0: | ||
formatted_line = f"<{DIM}>{summary}</{DIM}> {formatted_line}" | ||
lines.append(cparse(formatted_line)) | ||
else: | ||
# other uncategorised log line | ||
# shouldn't happen; tolerate unknown rsync implementation? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you don't think it should happen, then perhaps a message warning that this is an unexpected rsync implementation, please contact the dev team might be appropriate. |
||
lines.append(line) | ||
return lines | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seemed to be duplicating the work of
format_rsync_output()
, but removing allcannot delete non-empty directory:
lines, not just theopt
dirThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point of the
+++
prefix/suffix will have been to separate intendedrsync
output from any unexpected "junk" that might be output by the command / shell, ensuring that we only display what we need, even if the output differs from expectation in other ways.Why did you remove this? Just didn't like the look of it?
Remember that this code is used for more than just the dry-run check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the context I could gather in #5125, the only unwanted output that was being targeted was
cannot delete non-empty directory:
. This is implemented informat_reinstall_output()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This
rsync
command doesn't just apply to the dry-run check (which is passed throughformat_rsync_output
). And this prefix stripped out other potential output.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cylc-flow/cylc/flow/install.py
Lines 226 to 227 in 48d3d38
is at odds with
cylc-flow/cylc/flow/scripts/reinstall.py
Lines 346 to 348 in 48d3d38
The former seems to have been implemented to cover
cannot delete non-empty directory:
, there was no mention of any other potential rsync output in #5125. And the latter seems to have been implemented to deliberately include other potential rsync output in case the rsync implementation results in non-standard output format.Hence I am not sure we should be stripping other potential rsync output.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not at odds.
+++
prefix ensures that only the intended output lines get through.else
handles intended output lines that don't matchsend
ordel.
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cannot delete non-empty directory:
does not have+++
pre/suffixed to it (it is orthogonal to the%o %n%L
output format). It is always being stripped. Only lines that matchsend
ordel.
have+++
pre/suffixed anyway.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only case I can think of where some other potential output would make it through both bits of code is if the
%o
output format resulted in something other thansend
ordel.
. But that seems unlikely