11import json
22from collections .abc import Mapping , Sequence
3+ from tempfile import TemporaryFile
4+ from typing import IO , Literal
35
46type ConfigurationValue = (
57 bool
1315type Variables = Mapping [str , ConfigurationValue ]
1416type BackendConfig = str | Mapping [str , ConfigurationValue ]
1517type Environment = Mapping [str , str ]
18+ type StreamName = Literal ["stdout" ] | Literal ["stderr" ]
19+ type StreamNames = set [StreamName ]
20+
21+
22+ class Result :
23+ def __init__ (self , stdout : IO [str ] | None , stderr : IO [str ] | None ):
24+ self .stdout = stdout
25+ self .stderr = stderr
1626
1727
1828class Executor :
19- def execute (self , command : Sequence [str ], env : Environment | None ) -> None :
20- raise Exception ("NotImplementedException" )
29+ def execute (
30+ self ,
31+ command : Sequence [str ],
32+ environment : Environment | None = None ,
33+ stdout : IO [str ] | None = None ,
34+ stderr : IO [str ] | None = None ,
35+ ) -> None :
36+ raise NotImplementedError
37+
38+
39+ def _captures (capture : StreamNames | None , stream : StreamName ) -> bool :
40+ return capture is not None and stream in capture
41+
42+
43+ def _capture_stream (
44+ capture : StreamNames | None , stream : StreamName
45+ ) -> IO [str ] | None :
46+ if _captures (capture , stream ):
47+ return TemporaryFile (mode = "w+t" )
48+ return None
2149
2250
2351class Terraform :
@@ -41,7 +69,7 @@ def init(
4169 if reconfigure :
4270 command = command + ["-reconfigure" ]
4371
44- self ._executor .execute (command , env = environment )
72+ self ._executor .execute (command , environment = environment )
4573
4674 def plan (
4775 self ,
@@ -52,7 +80,7 @@ def plan(
5280 base_command = self ._build_base_command (chdir )
5381 command = base_command + ["plan" ] + self ._build_vars (vars )
5482
55- self ._executor .execute (command , env = environment )
83+ self ._executor .execute (command , environment = environment )
5684
5785 def apply (
5886 self ,
@@ -70,7 +98,7 @@ def apply(
7098 + self ._build_vars (vars )
7199 )
72100
73- self ._executor .execute (command , env = environment )
101+ self ._executor .execute (command , environment = environment )
74102
75103 def select_workspace (
76104 self ,
@@ -87,7 +115,43 @@ def select_workspace(
87115
88116 command = command + [workspace ]
89117
90- self ._executor .execute (command , env = environment )
118+ self ._executor .execute (command , environment = environment )
119+
120+ def output (
121+ self ,
122+ chdir : str | None = None ,
123+ name : str | None = None ,
124+ raw : bool = False ,
125+ json : bool = False ,
126+ environment : Environment | None = None ,
127+ capture : StreamNames | None = None ,
128+ ) -> Result :
129+ base_command = self ._build_base_command (chdir )
130+ command = base_command + ["output" ]
131+
132+ if raw :
133+ command = command + ["-raw" ]
134+ if json :
135+ command = command + ["-json" ]
136+ if name is not None :
137+ command = command + [name ]
138+
139+ stdout = _capture_stream (capture , "stdout" )
140+ stderr = _capture_stream (capture , "stderr" )
141+
142+ self ._executor .execute (
143+ command ,
144+ environment = environment ,
145+ stdout = stdout ,
146+ stderr = stderr ,
147+ )
148+
149+ if stdout is not None :
150+ stdout .seek (0 )
151+ if stderr is not None :
152+ stderr .seek (0 )
153+
154+ return Result (stdout , stderr )
91155
92156 @staticmethod
93157 def _build_base_command (chdir : str | None ) -> list [str ]:
0 commit comments