Skip to content

Commit

Permalink
[special-vars] Implement OIL_VERSION.
Browse files Browse the repository at this point in the history
ble.sh and neofetch both want to use it.

Addresses issue #683.

Unrelated: Start QSTR doc.
  • Loading branch information
Andy Chu committed Apr 8, 2020
1 parent 03f0b2d commit 8778a5c
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 20 deletions.
12 changes: 7 additions & 5 deletions bin/oil.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,8 @@ def _InitReadline(readline_mod, history_filename, root_comp, display, debug_f):
)


def _ShowVersion():
pyutil.ShowAppVersion('Oil')
def _ShowVersion(version_str):
pyutil.ShowAppVersion('Oil', version_str)


def SourceStartupFile(rc_path, lang, parse_ctx, cmd_ev):
Expand Down Expand Up @@ -323,9 +323,10 @@ def ShellMain(lang, argv0, argv, login_shell):
if opts.help:
builtin_misc.Help(['%s-usage' % lang], loader)
return 0
version_str = pyutil.GetVersion()
if opts.version:
# OSH version is the only binary in Oil right now, so it's all one version.
_ShowVersion()
_ShowVersion(version_str)
return 0

no_str = None # type: str
Expand All @@ -348,7 +349,7 @@ def ShellMain(lang, argv0, argv, login_shell):
errfmt = ui.ErrorFormatter(arena)

mem = state.Mem(dollar0, argv[arg_r.i + 1:], arena, debug_stack)
state.InitMem(mem, posix.environ)
state.InitMem(mem, posix.environ, version_str)
builtin_funcs.Init(mem)

procs = {}
Expand Down Expand Up @@ -898,7 +899,8 @@ def AppBundleMain(argv):
sys.exit(0)

if first_arg in ('-V', '--version'):
_ShowVersion()
version_str = pyutil.GetVersion()
_ShowVersion(version_str)
sys.exit(0)

main_name = first_arg
Expand Down
1 change: 1 addition & 0 deletions build/doc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ readonly MARKDOWN_DOCS=(
oil-proc-func-block
eggex
unicode
qstr

# Internal stuff
interpreter-state
Expand Down
2 changes: 1 addition & 1 deletion core/completion_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def _MakeRootCompleter(parse_ctx=None, comp_lookup=None):
debug_f = util.NullDebugFile()

mem = state.Mem('', [], None, [])
state.InitMem(mem, {})
state.InitMem(mem, {}, '0.1')

return completion.RootCompleter(ev, mem, comp_lookup, compopt_state,
comp_ui_state, parse_ctx, debug_f)
Expand Down
2 changes: 1 addition & 1 deletion core/process_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def Banner(msg):
_ARENA = test_lib.MakeArena('process_test.py')

_MEM = state.Mem('', [], _ARENA, [])
state.InitMem(_MEM, {})
state.InitMem(_MEM, {}, '0.1')

_OPT_ARRAY = [False] * option_i.ARRAY_SIZE
_PARSE_OPTS = optview.Parse(_OPT_ARRAY)
Expand Down
17 changes: 10 additions & 7 deletions core/pyutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,21 +121,25 @@ def GetResourceLoader():
return _loader


def ShowAppVersion(app_name):
# type: (str) -> None
"""For Oil and OPy."""
def GetVersion():
# type:() -> str
loader = GetResourceLoader()
f = loader.open('oil-version.txt')
version = f.readline().strip()
version_str = f.readline().strip()
f.close()
return version_str


def ShowAppVersion(app_name, version_str):
# type: (str, str) -> None
"""For Oil and OPy."""
loader = GetResourceLoader()
try:
f = loader.open('release-date.txt')
except IOError:
release_date = '-' # in dev tree
else:
release_date = f.readline().strip()
finally:
f.close()

try:
Expand All @@ -144,7 +148,6 @@ def ShowAppVersion(app_name):
pyc_version = '-' # in dev tree
else:
pyc_version = f.readline().strip()
finally:
f.close()

# node is like 'hostname'
Expand All @@ -167,7 +170,7 @@ def ShowAppVersion(app_name):
py_impl = 'CPython' if hasattr(sys, 'executable') else 'OVM'

# What C functions do these come from?
print('%s version %s' % (app_name, version))
print('%s version %s' % (app_name, version_str))
print('Release Date: %s' % release_date)
print('Arch: %s' % machine)
print('OS: %s' % system)
Expand Down
6 changes: 4 additions & 2 deletions core/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -641,12 +641,13 @@ def _InitVarsFromEnv(mem, environ):
lvalue.Named('PWD'), None, scope_e.GlobalOnly, flags=SetExport)


def InitMem(mem, environ):
# type: (Mem, Dict[str, str]) -> None
def InitMem(mem, environ, version_str):
# type: (Mem, Dict[str, str], version_str) -> None
"""
Initialize memory with shell defaults. Other interpreters could have
different builtin variables.
"""
SetGlobalString(mem, 'OIL_VERSION', version_str)
_InitDefaults(mem)
_InitVarsFromEnv(mem, environ)
# MUTABLE GLOBAL that's SEPARATE from $PWD. Used by the 'pwd' builtin, but
Expand Down Expand Up @@ -1570,6 +1571,7 @@ def IsGlobalScope(self):
# type: () -> bool
return len(self.var_stack) == 1


def SetLocalString(mem, name, s):
# type: (Mem, str, str) -> None
"""Set a local string.
Expand Down
6 changes: 3 additions & 3 deletions core/test_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def InitLexer(s, arena):
def InitWordEvaluator():
arena = MakeArena('<InitWordEvaluator>')
mem = state.Mem('', [], arena, [])
state.InitMem(mem, {})
state.InitMem(mem, {}, '0.1')

opt_array = [False] * option_i.ARRAY_SIZE
errexit = state._ErrExit()
Expand Down Expand Up @@ -159,7 +159,7 @@ def InitCommandEvaluator(parse_ctx=None, comp_lookup=None, arena=None, mem=None,
parse_ctx = InitParseContext()

mem = mem or state.Mem('', [], arena, [])
state.InitMem(mem, {})
state.InitMem(mem, {}, '0.1')
errexit = state._ErrExit()
exec_opts = optview.Exec(opt_array, errexit)
mutable_opts = state.MutableOpts(mem, opt_array, errexit, None)
Expand Down Expand Up @@ -251,7 +251,7 @@ def EvalCode(code_str, parse_ctx, comp_lookup=None, mem=None, aliases=None):

comp_lookup = comp_lookup or completion.Lookup()
mem = mem or state.Mem('', [], arena, [])
state.InitMem(mem, {})
state.InitMem(mem, {}, '0.1')

line_reader, _ = InitLexer(code_str, arena)
c_parser = parse_ctx.MakeOshParser(line_reader)
Expand Down
95 changes: 95 additions & 0 deletions doc/qstr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
in_progress: true
---

QSTR Serialization Format
=========================

We want a single way to serialize and parse arbitrary byte strings (which may
be encoded in UTF-8 or another encoding.)

- It should be safe to print arbitrary strings to terminals.
- Strings should fit on a line.

TODO: copy content from this page:
<https://github.com/oilshell/oil/wiki/CSTR-Proposal>

<div id="toc">
</div>

## Use Case: `set -x` format (`xtrace`)

Unquoted:

```
$ set -x
$ echo a b
+ echo a b
```

We need single quotes `'1 2'` to make arguments with spaces unambiguous:

```
$ set -x
$ x='a b'
$ echo "$x" c
+ echo 'a b' c
```

We need C-escaped strings `$'1\n2'` to make arguments with newlines fit on a
line:

```
$ set -x
$ x=$'a\nb'
$ echo "$x" c
+ echo $'a\nb' 3
```

And to show unprintable characters safely on a terminal:

```
$ set -x
$ x=$'\e\001'
$ echo "$x"
echo $'\x1b\x01'
```

## Design

- The `$''` emitter should be compatible with CSTR. These all mean the same thing:

```
$'\x01\n' # shell-compatible (but confusing)
c'\x01\n' # explicit CSTR
'\x01\n' # implicit CSTR, which is similar ro Python format
```

## Display Special Characters

### Three options For Displaying Unicode


1. Don't decode UTF-8. Just show bytes like `'\xce\xbc'`.
2. Decode UTF-8. This could be useful for showing at a glance if we have valid
UTF-8 strings.
a. Show code points like `'\u03bc'`. ASCII friendly, so better for weird
debugging situations.
b. Show them literally. Depends on the terminal.

### Special Chars Emitted

- `\r` `\n` `\t` `\0` (subset of C and shell; Rust has this)
- Everything else is either `\xFF` or `\u03bc`

## Links

- <https://doc.rust-lang.org/reference/tokens.html#string-literals> - Rust is
precise about it:
- `\x7F`
- `\u{03bc}` or `\u{0003bc}`. This is clearer than the bare format. And
there are bugs in octal in bash -- is it 3 or 4 chars, etc.?
- But bash's `$''` doesn't accept this.
- `\t` `\r` `\n`
- `\\`
- `\0`
2 changes: 1 addition & 1 deletion osh/arith_parse_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def ParseAndEval(code_str):
print('node:', anode)

mem = state.Mem('', [], arena, [])
state.InitMem(mem, {})
state.InitMem(mem, {}, '0.1')
parse_opts, exec_opts, mutable_opts = state.MakeOpts(mem, None)

splitter = split.SplitContext(mem)
Expand Down
25 changes: 25 additions & 0 deletions spec/special-vars.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -396,3 +396,28 @@ nonempty=0
## N-I dash status: 2
## N-I dash stdout-json: ""

#### BASH_VERSION / OIL_VERSION
case $SH in
(bash)
# BASH_VERSION=zz

echo $BASH_VERSION | egrep -o '4\.4\.0' > /dev/null
echo matched=$?
;;
(*osh)
# note: version string is mutable like in bash. I guess that's useful for
# testing? We might want a strict mode to eliminate that?

echo $OIL_VERSION | egrep -o '[0-9]\.[0-9]\.' > /dev/null
echo matched=$?
;;
(*)
echo 'no version'
;;
esac
## STDOUT:
matched=0
## END
## N-I dash/mksh/zsh STDOUT:
no version
## END

0 comments on commit 8778a5c

Please sign in to comment.