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

fix colon parsing, added debug logging, added resource header #47

Merged
merged 2 commits into from
Dec 26, 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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "tftui"
version = "0.10.2"
version = "0.10.3"
description = "Terraform Textual User Interface"
authors = ["Ido Avraham"]
license = "Apache-2.0"
Expand Down
10 changes: 8 additions & 2 deletions test/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,14 @@ module "mercury" {
input_number = random_integer.random_number.result
}

module "dotted" {
for_each = toset(["a.b", "c.d"])
module "dots" {
for_each = toset(["string.with.dots", "another.string.with.dots"])
source = "./module"
input_number = random_integer.random_number.result
}

module "colons" {
for_each = toset(["string:with:colons", "another:string:with:colons"])
source = "./module"
input_number = random_integer.random_number.result
}
Expand Down
36 changes: 34 additions & 2 deletions tftui/__main__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import argparse
import pyperclip
import os
import json
from tftui.apis import OutboundAPIs
from tftui.state import State, Block, execute_async, split_resource_name
from tftui.plan import execute_plan
from tftui.debug_log import setup_logging
from shutil import which
from textual import work
from textual.app import App, Binding
Expand All @@ -19,6 +21,8 @@
Button,
)

logger = setup_logging()


class ApplicationGlobals:
executable = "terraform"
Expand Down Expand Up @@ -75,7 +79,8 @@ def build_tree(self, search_string="") -> None:

filtered_blocks = dict(
filter(
lambda block: search_string in block[1].contents,
lambda block: search_string in block[1].contents
or search_string in block[1].name,
self.current_state.state_tree.items(),
)
)
Expand All @@ -85,6 +90,18 @@ def build_tree(self, search_string="") -> None:
if block.submodule != ""
}

logger.debug(
"Filter tree: %s",
json.dumps(
{
"search string": search_string,
"filtered blocks": len(filtered_blocks),
"filtered modules": len(modules),
},
indent=2,
),
)

for module_fullname in sorted(modules):
parts = split_resource_name(module_fullname)
submodule = ""
Expand Down Expand Up @@ -153,6 +170,11 @@ def on_tree_node_selected(self) -> None:
if not self.current_node.allow_expand:
self.app.resource.clear()
self.app.resource.write(self.current_node.data.contents)
self.app.switcher.border_title = (
f"{self.current_node.data.submodule}.{self.current_node.data.name}"
if self.current_node.data.submodule
else self.current_node.data.name
)
self.app.switcher.current = "resource"

def select_current_node(self) -> None:
Expand Down Expand Up @@ -341,6 +363,7 @@ def action_back(self) -> None:
):
return
self.switcher.current = "tree"
self.app.switcher.border_title = ""
self.tree.focus()

async def action_plan(self) -> None:
Expand Down Expand Up @@ -430,6 +453,7 @@ def action_collapse(self, level=0) -> None:
self.tree.root.expand()

def action_search(self) -> None:
self.switcher.border_title = ""
self.switcher.current = "tree"
self.search.focus()

Expand Down Expand Up @@ -459,6 +483,12 @@ def parse_command_line() -> None:
help="enable light mode (default dark)",
action="store_true",
)
parser.add_argument(
"-g",
"--generate-debug-log",
action="store_true",
help="generate debug log file (default disabled)",
)
parser.add_argument(
"-v", "--version", help="show version information", action="store_true"
)
Expand All @@ -473,8 +503,10 @@ def parse_command_line() -> None:
OutboundAPIs.disable_usage_tracking()
if args.executable:
ApplicationGlobals.executable = args.executable
if args.generate_debug_log:
logger = setup_logging("debug")
logger.debug("Debug log enabled")
ApplicationGlobals.darkmode = not args.light_mode

if (
which(ApplicationGlobals.executable) is None
and which(f"{ApplicationGlobals.executable}.exe") is None
Expand Down
18 changes: 18 additions & 0 deletions tftui/debug_log.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import logging


def setup_logging(log_level=None):
logger = logging.getLogger(__name__)
if log_level is not None:
numeric_level = getattr(logging, log_level.upper(), None)
logger.setLevel(numeric_level)
if not logger.handlers:
formatter = logging.Formatter(
"%(asctime)s [%(module)s:%(funcName)s] %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
file_handler = logging.FileHandler("tftui.log")
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)

return logger
3 changes: 3 additions & 0 deletions tftui/plan.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import asyncio
from tftui.debug_log import setup_logging

logger = setup_logging()


async def execute_plan(executable: str, console) -> tuple[int, str]:
Expand Down
36 changes: 34 additions & 2 deletions tftui/state.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import asyncio
import re
import logging
import json
from collections import Counter
from tftui.debug_log import setup_logging

logger = setup_logging()


async def execute_async(*command: str) -> tuple[str, str]:
Expand All @@ -13,7 +19,10 @@ async def execute_async(*command: str) -> tuple[str, str]:

stdout, strerr = await proc.communicate()
response = stdout.decode("utf-8")

logger.debug(
"Executed command: %s",
json.dumps({"command": command, "return_code": proc.returncode}, indent=2),
)
return (proc.returncode, response)


Expand Down Expand Up @@ -50,7 +59,7 @@ def __init__(self, executable="terraform", no_init=False):
self.no_init = no_init

def parse_block(line: str) -> tuple[str, str, str]:
fullname = line[2 : line.find(":")]
fullname = line[2 : line.rindex(":")]
is_tainted = line.endswith("(tainted)")
parts = split_resource_name(fullname)
if fullname.startswith("data") or ".data." in fullname:
Expand All @@ -61,6 +70,7 @@ def parse_block(line: str) -> tuple[str, str, str]:
name = ".".join(parts[-2:])
submodule = ".".join(parts[:-2])
type = Block.TYPE_RESOURCE

return (fullname, name, submodule, type, is_tainted)

async def refresh_state(self) -> None:
Expand All @@ -81,6 +91,28 @@ async def refresh_state(self) -> None:
else:
contents += line.rstrip() + "\n"

if logger.isEnabledFor(logging.DEBUG):
for key, block in self.state_tree.items():
logger.debug(
"Parsed block: %s",
json.dumps(
{
"fullname": key,
"module": block.submodule,
"name": block.name,
"lines": block.contents.count("\n"),
"tainted": block.is_tainted,
},
indent=2,
),
)
logger.debug(
"Total blocks: %s",
json.dumps(
Counter(block.type for block in self.state_tree.values()), indent=2
),
)


if __name__ == "__main__":
state = State()
Expand Down
1 change: 1 addition & 0 deletions tftui/ui.tcss
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@

#switcher {
border: double lightblue;
border_title_align: center;
max-height: 75vh;
}

Expand Down