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

Clean up ast modules and logging #674

Merged
merged 5 commits into from
May 22, 2023
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
1 change: 0 additions & 1 deletion compiler/ast_to_ir.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from shell_ast.ast_util import *
from ir import *
from shell_ast.ast_node import *
from shell_ast.ast_node_c import *
from util import *
from parse import from_ast_objects_to_shell
from shell_ast.expand import *
Expand Down
20 changes: 20 additions & 0 deletions compiler/config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import logging
import os
import subprocess
import math
Expand Down Expand Up @@ -55,6 +56,25 @@ def set_config_globals_from_pash_args(given_pash_args):
DEBUG_LEVEL = pash_args.debug
LOG_FILE = pash_args.log_file

## Also set logging here
# Format logging
# ref: https://docs.python.org/3/library/logging.html#formatter-objects
## TODO: When we add more logging levels bring back the levelname+time
if given_pash_args.log_file == "":
logging.basicConfig(format="%(message)s")
else:
logging.basicConfig(format="%(message)s",
filename=f"{os.path.abspath(given_pash_args.log_file)}",
filemode="w")

# Set debug level
if given_pash_args.debug == 1:
logging.getLogger().setLevel(logging.INFO)
elif given_pash_args.debug == 2:
logging.getLogger().setLevel(logging.DEBUG)
elif given_pash_args.debug >= 3:
logging.getLogger().setLevel(logging.TRACE)


## Increase the recursion limit (it seems that the parser/unparser needs it for bigger graphs)
sys.setrecursionlimit(10000)
Expand Down
4 changes: 0 additions & 4 deletions compiler/definitions/no_match_exception.py

This file was deleted.

55 changes: 0 additions & 55 deletions compiler/pash.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ def main():
if(len(args.input) == 0 or args.interactive):
log("ERROR: --interactive option is not supported!", level=0)
assert(False)
## This should never be used!
interactive(args, shell_name)
else:
input_script_path = args.input[0]
input_script_arguments = args.input[1:]
Expand Down Expand Up @@ -61,59 +59,6 @@ def preprocess_and_execute_asts(input_script_path, args, input_script_arguments,

return return_code

## TODO: Create an interactive pash
def interactive(args, shell_name):
## This means that we are interactive
assert(len(args.input) == 0 or args.interactive)

if len(args.input) == 0:
## Read from stdin
input_script_path = "-"
script_args = []
else:
input_script_path = args.input[0]
script_args = args.input[1:]

## Spawn a bash shell in interactive mode
new_env = shell_env(shell_name)
subprocess_args = bash_prefix_args()
## Add this option to read code from stdin
subprocess_args.append("-s")
## Add the script arguments here
subprocess_args += script_args
with subprocess.Popen(subprocess_args,
env=new_env,
stdin=subprocess.PIPE,
universal_newlines=True,
close_fds=False) as shell_proc:
## TODO: Do we need to pipe stdout/stderror

## First send an exec so that we change the name of the shell
##
## TODO: Can this be done in a less ad-hoc way?
command = bash_exec_string(shell_name)
shell_proc.stdin.write(command)

## For each parsed AST:
## 1. Preprocess it
## 2. Translate it to shell syntax
## 3. Send it to the interactive bash
ast_objects = parse_shell_to_asts_interactive(input_script_path)
for ast_object in ast_objects:
## Preprocess each ast object and produce a preprocessed shell script fragment
preprocessed_shell_script = preprocess([ast_object], args)
log("Sending script to shell process...")
## Send the preprocessed script fragment to the shell process
shell_proc.stdin.write(preprocessed_shell_script)
shell_proc.stdin.flush()

## Close the input and wait for the internal process to finish
shell_proc.stdin.close()
shell_proc.wait()

log("-" * 40) #log end marker
## Return the exit code of the executed script
sys.exit(shell_proc.returncode)


def parse_args():
Expand Down
5 changes: 1 addition & 4 deletions compiler/shell_ast/ast_node.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
from json import JSONEncoder

from shell_ast.ast_node_c import *
from definitions.no_match_exception import *
from util import *

from util import make_kv

class AstNode:
NodeName = 'None'
Expand Down
17 changes: 0 additions & 17 deletions compiler/shell_ast/ast_node_c.py

This file was deleted.

25 changes: 16 additions & 9 deletions compiler/shell_ast/expand.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import copy
import logging

from shell_ast.ast_node import *
from shell_ast.ast_node_c import *
from shell_ast import ast_util

import ast_to_ir
## TODO: Remove use of get_kv when we make all ast objects classes
from util import get_kv

## TODO: Make this a global variable that is set so that it can be used as a library
import config
## Could be useful for debugging
# import parse
Expand All @@ -12,6 +16,9 @@
# SAFE EXPANSION ANALYSIS
################################################################################

def log(msg: str):
logging.info('Expansion: {msg}')

## This function checks if a word is safe to expand (i.e. if it will
## not have unpleasant side-effects)
def safe_to_expand(arg_char):
Expand Down Expand Up @@ -126,14 +133,14 @@ def safe_command(command):
# TODO 2020-11-24 MMG which commands are safe to run in advance?
# TODO 2020-11-24 MMG how do we differentiate it being safe to do nested expansions?
global safe_cases
return ast_to_ir.ast_match(command, safe_cases)
return ast_util.ast_match(command, safe_cases)

def safe_pipe(node):
return False

safe_commands = ["echo", ":"]

def safe_simple(node):
def safe_simple(node: CommandNode):
# TODO 2020-11-25 check redirs, assignments

if (len(node.arguments) <= 0):
Expand Down Expand Up @@ -305,7 +312,7 @@ def lookup_variable_inner_unsafe(varname):
def is_u_set():
## This variable is set by pash and is exported and therefore will be in the variable file.
_type, value = config.config['shell_variables']["pash_previous_set_status"]
# log("Previous set status is:", value)
# log(f'Previous set status is: {value}')
return "u" in value


Expand Down Expand Up @@ -383,8 +390,8 @@ def char_code(c):
return [type, ord(c)]

def expand_arg(arg_chars, config, quoted = False):
# log("expanding arg", arg_chars)
# log("unparsed_string:", parse.pash_string_of_arg(arg_chars))
# log(f'expanding arg {arg_chars}")
# log(f"unparsed_string: {parse.pash_string_of_arg(arg_chars)}")
res = []
for arg_char in arg_chars:
new = expand_arg_char(arg_char, quoted, config)
Expand Down Expand Up @@ -440,7 +447,7 @@ def expand_var(fmt, null, var, arg, quoted, config):

_type, value = lookup_variable(var, config)

log("Var:", var, "value:", value)
log(f'Var: {var} value: {value}')

if isinstance(value, InvalidVariable):
raise StuckExpansion("couldn't expand invalid variable", value)
Expand Down Expand Up @@ -518,7 +525,7 @@ def expand_command(command, config):
# TODO 2020-11-24 MMG which commands are safe to run in advance?
# TODO 2020-11-24 MMG how do we differentiate it being safe to do nested expansions?
global expand_cases
return ast_to_ir.ast_match(command, expand_cases, config)
return ast_util.ast_match(command, expand_cases, config)

def expand_pipe(node, config):
for i, n in enumerate(node.items):
Expand Down
14 changes: 5 additions & 9 deletions compiler/util.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from datetime import timedelta
import functools
import logging
from typing import Optional, TypeVar, Union, List, Any
TType = TypeVar("TType")
import os
Expand Down Expand Up @@ -44,18 +45,13 @@ def wrapper(*args, **kwargs):
return decorator

## This is a wrapper for prints
##
## TODO: Extend the configuration to allow for custom file to output PaSh log. This would
## allow us to not pollute the .time files.
def log(*args, end='\n', level=1):
## If the debug logging level is at least
## as high as this log message.
if (config.DEBUG_LEVEL >= level):
if(config.LOG_FILE == ""):
print(config.LOGGING_PREFIX, *args, file=sys.stderr, end=end, flush=True)
else:
with open(config.LOG_FILE, "a") as f:
print(config.LOGGING_PREFIX, *args, file=f, end=end, flush=True)
## TODO: Allow all levels
if level >= 1:
concatted_args = " ".join([str(a) for a in list(args)])
logging.info(f'{config.LOGGING_PREFIX} {concatted_args}')

def ptempfile():
fd, name = tempfile.mkstemp(dir=config.PASH_TMP_PREFIX)
Expand Down