Skip to content
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

Remove useless text editor config. #4993

Merged
merged 3 commits into from
Jul 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ Jinja2 used by Cylc from 2.11 to 3.0.
[#4896](https://github.com/cylc/cylc-flow/pull/4896) - Allow the setting of
default job runner directives for platforms.

[#4993](https://github.com/cylc/cylc-flow/pull/4993) - Remove the few remaining
uses of a configured text editor (via `cylc view` and `cylc cat-log` options).
The primary uses of it (`cylc trigger --edit` and `cylc edit` in Cylc 7) have
already been removed from Cylc 8.


### Fixes

[#4984](https://github.com/cylc/cylc-flow/pull/4984) -
Expand Down
59 changes: 0 additions & 59 deletions cylc/flow/cfgspec/globalcfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -1075,55 +1075,6 @@ def default_for(

.. versionadded:: 8.0.0
""")

with Conf('editors', desc='''
hjoliver marked this conversation as resolved.
Show resolved Hide resolved
Choose your favourite text editor for editing workflow configurations.
'''):
Conf('terminal', VDR.V_STRING, desc='''
An in-terminal text editor to be used by the Cylc command line.

If unspecified Cylc will use the environment variable
``$EDITOR`` which is the preferred way to set your text editor.

.. Note::

You can set your ``$EDITOR`` in your shell profile file
(e.g. ``~.bashrc``)

If neither this or ``$EDITOR`` are specified then Cylc will
default to ``vi``.

Examples::

ed
emacs -nw
nano
vi
''')
Conf('gui', VDR.V_STRING, desc='''
A graphical text editor to be used by cylc.

If unspecified Cylc will use the environment variable
``$GEDITOR`` which is the preferred way to set your text editor.

.. Note::

You can set your ``$GEDITOR`` in your shell profile file
(e.g. ``~.bashrc``)

If neither this or ``$GEDITOR`` are specified then Cylc will
default to ``gvim -fg``.

Examples::

atom --wait
code --new-window --wait
emacs
gedit -s
gvim -fg
nedit
''')

with Conf('platforms', desc='''
Platforms allow you to define compute resources available at your
site.
Expand Down Expand Up @@ -1924,7 +1875,6 @@ def load(self) -> None:
# Flesh out with defaults
self.expand()

self._set_default_editors()
self._no_platform_group_name_overlap()
with suppress(KeyError):
validate_platforms(self.sparse['platforms'])
Expand All @@ -1946,15 +1896,6 @@ def _validate_source_dirs(self) -> None:
keys, value=item, msg="must be an absolute path"
)

def _set_default_editors(self):
# default to $[G]EDITOR unless an editor is defined in the config
# NOTE: use `or` to handle cases where an env var is set to ''
cfg = self.get(sparse=False)
if not cfg['editors']['terminal']:
cfg['editors']['terminal'] = os.environ.get('EDITOR') or 'vi'
if not cfg['editors']['gui']:
cfg['editors']['gui'] = os.environ.get('GEDITOR') or 'gvim -fg'

def _no_platform_group_name_overlap(self):
if (
'platforms' in self.sparse and
Expand Down
89 changes: 11 additions & 78 deletions cylc/flow/scripts/cat_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@

View Cylc workflow and job log files.

Print, view-in-editor, or tail-follow content, print path, or list directory,
of local or remote task job and scheduler logs. Job runner view commands
(e.g. 'qcat') are used if defined in global config and the job is running.
Print, tail-follow, print path, or list directory, of local or remote task job
and scheduler logs. Job runner view commands (e.g. 'qcat') are used if defined
in global config and the job is running.

For standard log types use the short-cut option argument or full filename (e.g.
for job stdout "-f o" or "-f job.out" will do).
Expand Down Expand Up @@ -57,13 +57,10 @@
from glob import glob
from pathlib import Path
import shlex
from stat import S_IRUSR
from subprocess import Popen, PIPE, DEVNULL
import sys
from tempfile import NamedTemporaryFile
from typing import TYPE_CHECKING

from cylc.flow.cfgspec.glbl_cfg import glbl_cfg
from cylc.flow.exceptions import InputError
import cylc.flow.flags
from cylc.flow.hostuserutil import is_remote_platform
Expand Down Expand Up @@ -121,7 +118,6 @@
'd': 'print-dir',
'c': 'cat',
't': 'tail',
'e': 'edit'
}


Expand Down Expand Up @@ -185,20 +181,8 @@ def view_log(logpath, mode, tailer_tmpl, batchview_cmd=None, remote=False,
for entry in sorted(os.listdir(os.path.dirname(logpath))):
print(entry)
return 0
elif not remote and mode == 'edit':
# Copy the log to a temporary read-only file for viewing in editor.
# Copy only BUFSIZE bytes at time, in case the file is huge.
outfile = NamedTemporaryFile()
with open(logpath, 'rb') as log:
data = log.read(BUFSIZE)
while data:
outfile.write(data)
data = log.read(BUFSIZE)
os.chmod(outfile.name, S_IRUSR)
outfile.seek(0, 0)
return outfile
elif mode == 'cat' or (remote and mode == 'edit'):
# Just cat file contents to stdout.
elif mode == 'cat':
# print file contents to stdout.
if batchview_cmd is not None:
cmd = shlex.split(batchview_cmd)
else:
Expand Down Expand Up @@ -264,11 +248,6 @@ def get_option_parser() -> COP:
help="Job submit number (default=%s, i.e. latest)." % NN,
metavar="INT", action="store", dest="submit_num", default=NN)

parser.add_option(
hjoliver marked this conversation as resolved.
Show resolved Hide resolved
"-g", "--geditor",
help="edit mode: use your configured GUI editor.",
action="store_true", default=False, dest="geditor")

parser.add_option(
"--remote-arg",
help="(for internal use: continue processing on job host)",
Expand Down Expand Up @@ -300,33 +279,6 @@ def get_task_job_attrs(workflow_id, point, task, submit_num):
return (task_job_data["platform_name"], job_runner_name, live_job_id)


def tmpfile_edit(tmpfile, geditor=False):
"""Edit a temporary read-only file containing the string filestr.

Detect and warn if the user forcibly writes to the temporary file.

"""
if geditor:
editor = glbl_cfg().get(['editors', 'gui'])
else:
editor = glbl_cfg().get(['editors', 'terminal'])
modtime1 = os.stat(tmpfile.name).st_mtime
cmd = shlex.split(editor)
cmd.append(tmpfile.name)
proc = Popen(cmd, stderr=PIPE) # nosec
# * editor command is user configurable
err = proc.communicate()[1].decode()
ret_code = proc.wait()
if ret_code == 0 and os.stat(tmpfile.name).st_mtime > modtime1:
sys.stderr.write(
'WARNING: you edited a TEMPORARY COPY of %s\n' % (
os.path.basename(tmpfile.name)
)
)
if ret_code and err:
sys.stderr.write(err)


@cli_function(get_option_parser)
def main(
parser: COP,
Expand All @@ -337,7 +289,7 @@ def main(
"""Implement cylc cat-log CLI.

Determine log path, user@host, batchview_cmd, and action (print, dir-list,
cat, edit, or tail), and then if the log path is:
cat, or tail), and then if the log path is:
a) local: perform action on log path, or
b) remote: re-invoke cylc cat-log as a) on the remote account

Expand Down Expand Up @@ -387,8 +339,6 @@ def main(
out = view_log(logpath, mode, tail_tmpl, color=color)
if out == 1:
sys.exit(1)
if mode == 'edit':
tmpfile_edit(out, options.geditor)
return

else:
Expand Down Expand Up @@ -452,29 +402,15 @@ def main(
if batchview_cmd:
cmd.append('--remote-arg=%s' % shlex.quote(batchview_cmd))
cmd.append(workflow_id)
is_edit_mode = (mode == 'edit')
# TODO: Add Intelligent Host selection to this
try:
proc = remote_cylc_cmd(
with suppress(KeyboardInterrupt):
# (Ctrl-C while tailing)
remote_cylc_cmd(
cmd,
platform,
capture_process=is_edit_mode,
capture_process=False,
manage=(mode == 'tail')
)
except KeyboardInterrupt:
# Ctrl-C while tailing.
pass
else:
if is_edit_mode:
# Write remote stdout to a temp file for viewing in editor.
# Only BUFSIZE bytes at a time in case huge stdout volume.
out = NamedTemporaryFile()
data = proc.stdout.read(BUFSIZE)
while data:
out.write(data)
data = proc.stdout.read(BUFSIZE)
os.chmod(out.name, S_IRUSR)
out.seek(0, 0)
else:
# Local task job or local job log.
logpath = os.path.normpath(get_workflow_run_job_dir(
Expand All @@ -483,7 +419,4 @@ def main(
tail_tmpl = os.path.expandvars(platform["tail command template"])
out = view_log(logpath, mode, tail_tmpl, batchview_cmd,
color=color)
if mode != 'edit':
sys.exit(out)
if mode == 'edit':
tmpfile_edit(out, options.geditor)
sys.exit(out)
83 changes: 8 additions & 75 deletions cylc/flow/scripts/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,15 @@

"""cylc view [OPTIONS] ARGS

View a processed workflow configuration.
Print a processed workflow configuration.

Note:
This is different to `cylc config` which displays the parsed
configuration (as Cylc would see it).

View a read-only temporary copy of workflow NAME's flow.cylc file, in your
editor, after optional include-file inlining and Jinja2 preprocessing.

The edit process is spawned in the foreground as follows:
$ <editor> flow.cylc
Where <editor> can be set in cylc global config.
"""

import os
import shlex
from subprocess import call
import sys
from tempfile import NamedTemporaryFile
from typing import TYPE_CHECKING

from cylc.flow.cfgspec.glbl_cfg import glbl_cfg
from cylc.flow.exceptions import CylcError
from cylc.flow.id_cli import parse_id
from cylc.flow.option_parsers import (
WORKFLOW_ID_OR_PATH_ARG_DOC,
Expand Down Expand Up @@ -107,14 +93,6 @@ def get_option_parser():
"not correspond to those reported by the parser).",
action="store_true", default=False, dest="cat")

parser.add_option(
"--gui", "-g", help="Force use of the configured GUI editor.",
action="store_true", default=False, dest="geditor")

parser.add_option(
"--stdout", help="Print the workflow definition to stdout.",
action="store_true", default=False, dest="stdout")

return parser


Expand All @@ -126,11 +104,6 @@ def main(parser: COP, options: 'Values', workflow_id: str) -> None:
constraint='workflows',
)

if options.geditor:
editor = glbl_cfg().get(['editors', 'gui'])
else:
editor = glbl_cfg().get(['editors', 'terminal'])

# read in the flow.cylc file
viewcfg = {
'mark': options.mark,
Expand All @@ -142,51 +115,11 @@ def main(parser: COP, options: 'Values', workflow_id: str) -> None:
'inline': (options.inline or options.jinja2 or options.empy
or options.process),
}
lines = read_and_proc(
for line in read_and_proc(
flow_file,
load_template_vars(options.templatevars, options.templatevars_file),
viewcfg=viewcfg)

if options.stdout:
for line in lines:
print(line)
sys.exit(0)

# write to a temporary file
viewfile = NamedTemporaryFile(
suffix=".flow.cylc", prefix=workflow_id.replace('/', '_') + '.',
)
for line in lines:
viewfile.write((line + '\n').encode())
viewfile.seek(0, 0)

# set the file to be read only
os.chmod(viewfile.name, 0o400)

# capture the temp file's mod time in case the user edits it
# and overrides the readonly mode.
modtime1 = os.stat(viewfile.name).st_mtime

# in case editor has options, e.g. 'emacs -nw':
command_list = shlex.split(editor)
command_list.append(viewfile.name)
command = ' '.join(command_list)
# THIS BLOCKS UNTIL THE COMMAND COMPLETES
retcode = call(command_list) # nosec (editor command is user configurable)
if retcode != 0:
# the command returned non-zero exist status
raise CylcError(f'{command} failed: {retcode}')

# !!!VIEWING FINISHED!!!

# Did the user edit the file
modtime2 = os.stat(viewfile.name).st_mtime

if modtime2 > modtime1:
print(
"\nWARNING: YOU HAVE EDITED A TEMPORARY READ-ONLY COPY "
f"OF THE WORKFLOW:\n {viewfile.name}\n",
file=sys.stderr
)
# DONE
viewfile.close()
load_template_vars(
options.templatevars, options.templatevars_file
),
viewcfg=viewcfg
):
print(line)
Loading