tinybird 0.0.1.dev28__py3-none-any.whl → 0.0.1.dev30__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of tinybird might be problematic. Click here for more details.

@@ -0,0 +1,182 @@
1
+ import os
2
+ import re
3
+ from os import getcwd
4
+ from pathlib import Path
5
+ from typing import Optional
6
+
7
+ import click
8
+
9
+ from tinybird.client import TinyB
10
+ from tinybird.prompts import mock_prompt, update_prompt
11
+ from tinybird.tb.modules.cli import cli
12
+ from tinybird.tb.modules.common import check_user_token_with_client, coro, generate_datafile
13
+ from tinybird.tb.modules.config import CLIConfig
14
+ from tinybird.tb.modules.datafile.fixture import build_fixture_name, persist_fixture
15
+ from tinybird.tb.modules.exceptions import CLIException
16
+ from tinybird.tb.modules.feedback_manager import FeedbackManager
17
+ from tinybird.tb.modules.llm import LLM
18
+ from tinybird.tb.modules.llm_utils import extract_xml, parse_xml
19
+ from tinybird.tb.modules.local_common import get_tinybird_local_client
20
+
21
+
22
+ @cli.command()
23
+ @click.argument("prompt")
24
+ @click.option(
25
+ "--folder",
26
+ default=".",
27
+ type=click.Path(exists=False, file_okay=False),
28
+ help="Folder where project files will be placed",
29
+ )
30
+ @coro
31
+ async def update(
32
+ prompt: str,
33
+ folder: str,
34
+ ) -> None:
35
+ """Update resources in the project."""
36
+ folder = folder or getcwd()
37
+ folder_path = Path(folder)
38
+ if not folder_path.exists():
39
+ folder_path.mkdir()
40
+
41
+ try:
42
+ config = CLIConfig.get_project_config(folder)
43
+ tb_client = config.get_client()
44
+ user_token: Optional[str] = None
45
+ try:
46
+ user_token = config.get_user_token()
47
+ if not user_token:
48
+ raise CLIException("No user token found")
49
+ await check_user_token_with_client(tb_client, token=user_token)
50
+ except Exception as e:
51
+ click.echo(
52
+ FeedbackManager.error(message=f"This action requires authentication. Run 'tb login' first. Error: {e}")
53
+ )
54
+ return
55
+
56
+ local_client = await get_tinybird_local_client(folder)
57
+
58
+ click.echo(FeedbackManager.highlight(message="\n» Updating resources..."))
59
+ datasources_updated = await update_resources(tb_client, user_token, prompt, folder)
60
+ click.echo(FeedbackManager.success(message="✓ Done!\n"))
61
+
62
+ if datasources_updated and user_token:
63
+ click.echo(FeedbackManager.highlight(message="\n» Generating fixtures..."))
64
+
65
+ datasource_files = [f for f in os.listdir(Path(folder) / "datasources") if f.endswith(".datasource")]
66
+ for datasource_file in datasource_files:
67
+ datasource_path = Path(folder) / "datasources" / datasource_file
68
+ llm = LLM(user_token=user_token, client=tb_client)
69
+ datasource_name = datasource_path.stem
70
+ datasource_content = datasource_path.read_text()
71
+ has_json_path = "`json:" in datasource_content
72
+ if has_json_path:
73
+ prompt = f"<datasource_schema>{datasource_content}</datasource_schema>\n<user_input>{prompt}</user_input>"
74
+ response = await llm.ask(prompt, system_prompt=mock_prompt(rows=20))
75
+ sql = extract_xml(response, "sql")
76
+ sql = sql.split("FORMAT")[0]
77
+ result = await local_client.query(f"{sql} FORMAT JSON")
78
+ data = result.get("data", [])
79
+ fixture_name = build_fixture_name(
80
+ datasource_path.absolute().as_posix(), datasource_name, datasource_content
81
+ )
82
+ if data:
83
+ persist_fixture(fixture_name, data, folder)
84
+ click.echo(FeedbackManager.info(message=f"✓ /fixtures/{datasource_name}"))
85
+
86
+ click.echo(FeedbackManager.success(message="✓ Done!\n"))
87
+ except Exception as e:
88
+ click.echo(FeedbackManager.error(message=f"Error: {str(e)}"))
89
+
90
+
91
+ async def update_resources(
92
+ tb_client: TinyB,
93
+ user_token: str,
94
+ prompt: str,
95
+ folder: str,
96
+ ):
97
+ datasource_paths = [
98
+ Path(folder) / "datasources" / f for f in os.listdir(Path(folder) / "datasources") if f.endswith(".datasource")
99
+ ]
100
+ pipes_paths = [
101
+ Path(folder) / "endpoints" / f for f in os.listdir(Path(folder) / "endpoints") if f.endswith(".pipe")
102
+ ]
103
+ resources_xml = "\n".join(
104
+ [
105
+ f"<resource><type>{resource_type}</type><name>{resource_name}</name><content>{resource_content}</content></resource>"
106
+ for resource_type, resource_name, resource_content in [
107
+ ("datasource", ds.stem, ds.read_text()) for ds in datasource_paths
108
+ ]
109
+ + [
110
+ (
111
+ "pipe",
112
+ pipe.stem,
113
+ pipe.read_text(),
114
+ )
115
+ for pipe in pipes_paths
116
+ ]
117
+ ]
118
+ )
119
+ llm = LLM(user_token=user_token, client=tb_client)
120
+ result = await llm.ask(prompt, system_prompt=update_prompt(resources_xml))
121
+ result = extract_xml(result, "response")
122
+ resources = parse_xml(result, "resource")
123
+ datasources = []
124
+ pipes = []
125
+ for resource_xml in resources:
126
+ resource_type = extract_xml(resource_xml, "type")
127
+ name = extract_xml(resource_xml, "name")
128
+ content = extract_xml(resource_xml, "content")
129
+ resource = {
130
+ "name": name,
131
+ "content": content,
132
+ }
133
+ if resource_type.lower() == "datasource":
134
+ datasources.append(resource)
135
+ elif resource_type.lower() == "pipe":
136
+ pipes.append(resource)
137
+
138
+ for ds in datasources:
139
+ content = ds["content"].replace("```", "")
140
+ filename = f"{ds['name']}.datasource"
141
+ generate_datafile(
142
+ content,
143
+ filename=filename,
144
+ data=None,
145
+ _format="ndjson",
146
+ force=True,
147
+ folder=folder,
148
+ )
149
+
150
+ for pipe in pipes:
151
+ content = pipe["content"].replace("```", "")
152
+ generate_pipe_file(pipe["name"], content, folder)
153
+
154
+ return len(datasources) > 0
155
+
156
+
157
+ def generate_pipe_file(name: str, content: str, folder: str):
158
+ def is_copy(content: str) -> bool:
159
+ return re.search(r"TYPE copy", content, re.IGNORECASE) is not None
160
+
161
+ def is_materialization(content: str) -> bool:
162
+ return re.search(r"TYPE materialized", content, re.IGNORECASE) is not None
163
+
164
+ def is_sink(content: str) -> bool:
165
+ return re.search(r"TYPE sink", content, re.IGNORECASE) is not None
166
+
167
+ if is_copy(content):
168
+ pathname = "copies"
169
+ elif is_materialization(content):
170
+ pathname = "materializations"
171
+ elif is_sink(content):
172
+ pathname = "sinks"
173
+ else:
174
+ pathname = "endpoints"
175
+
176
+ base = Path(folder) / pathname
177
+ if not base.exists():
178
+ base = Path()
179
+ f = base / (f"{name}.pipe")
180
+ with open(f"{f}", "w") as file:
181
+ file.write(content)
182
+ click.echo(FeedbackManager.info_file_created(file=f.relative_to(folder)))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tinybird
3
- Version: 0.0.1.dev28
3
+ Version: 0.0.1.dev30
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -8,6 +8,7 @@ Author-email: support@tinybird.co
8
8
  Requires-Python: >=3.9, <3.13
9
9
  Description-Content-Type: text/x-rst
10
10
  Requires-Dist: aiofiles (==24.1.0)
11
+ Requires-Dist: anthropic (==0.42.0)
11
12
  Requires-Dist: click (<8.2,>=8.1.6)
12
13
  Requires-Dist: clickhouse-toolset (==0.33.dev0)
13
14
  Requires-Dist: colorama (==0.4.6)
@@ -1,12 +1,12 @@
1
1
  tinybird/__cli__.py,sha256=pgYsVLcqL16wtSn6KtKweNZYoYJdEksTgSvQAW7hH64,250
2
- tinybird/client.py,sha256=xM9Czi9JRjt3VpTAoe2di4m36VYIT3ngpn-DgkWFv-Y,51505
2
+ tinybird/client.py,sha256=P-bc7s7SbrnzkZkSsb_TO58q4Jxy-bBD5S5qpYiXiZg,51517
3
3
  tinybird/config.py,sha256=RRNb3Z1zkykTpusBTSyszuIySHGMsfL5aVxxt1kdr6w,6147
4
4
  tinybird/connectors.py,sha256=lkpVSUmSuViEZBa4QjTK7YmPHUop0a5UFoTrSmlVq6k,15244
5
5
  tinybird/context.py,sha256=kutUQ0kCwparowI74_YLXx6wtTzGLRouJ6oGHVBPzBo,1291
6
6
  tinybird/datatypes.py,sha256=XNypumfqNjsvLJ5iNXnbVHRvAJe0aQwI3lS6Cxox-e0,10979
7
7
  tinybird/feedback_manager.py,sha256=cNUbt0Jxim02UiIdlyP12DJfXfFFzxDCfJK9XRWZ9A0,67488
8
8
  tinybird/git_settings.py,sha256=Sw_8rGmribEFJ4Z_6idrVytxpFYk7ez8ei0qHULzs3E,3934
9
- tinybird/prompts.py,sha256=ZZ13gs6FzRr-oQ3W0kkZG5PAYd3HI7iJQ3WMqxIaMv8,28580
9
+ tinybird/prompts.py,sha256=xrZMZykphO9DRfW5yvCJNZMhPq0v1zab3d9jKy9plhU,24064
10
10
  tinybird/sql.py,sha256=eulpRe05ZFrKFrxYawgxDxxrktFE8uL6hSL1gHIWKyg,46166
11
11
  tinybird/sql_template.py,sha256=IqYRfUxDYBCoOYjqqvn--_8QXLv9FSRnJ0bInx7q1Xs,93051
12
12
  tinybird/sql_template_fmt.py,sha256=1z-PuqSZXtzso8Z_mPqUc-NxIxUrNUcVIPezNieZk-M,10196
@@ -15,44 +15,45 @@ tinybird/syncasync.py,sha256=IPnOx6lMbf9SNddN1eBtssg8vCLHMt76SuZ6YNYm-Yk,27761
15
15
  tinybird/tornado_template.py,sha256=oflXyoL2LSCegvl6bAzqw2JIqRaN5WPjhYYDtQcfuOE,41869
16
16
  tinybird/ch_utils/constants.py,sha256=aYvg2C_WxYWsnqPdZB1ZFoIr8ZY-XjUXYyHKE9Ansj0,3890
17
17
  tinybird/ch_utils/engine.py,sha256=OXkBhlzGjZotjD0vaT-rFIbSGV4tpiHxE8qO_ip0SyQ,40454
18
- tinybird/tb/__cli__.py,sha256=oSnwZedLkWynsHicPpwRFJasCfsEVp6i_ZEM1_xCwYs,251
19
- tinybird/tb/cli.py,sha256=D5Xs9RPbBY6U6lXTtzRSWNs2pG6uSzax-cfoKMpO7Jg,889
18
+ tinybird/tb/__cli__.py,sha256=6hEdXKgx0nKv06KQFvgIz7SfdCIFDW1PO1n92A31kH4,251
19
+ tinybird/tb/cli.py,sha256=dmrf8O9cqBuOYUmVBbNDSNQpHUhBg6IkBPaISAj4kHo,923
20
20
  tinybird/tb/modules/auth.py,sha256=EzRWFmwRkXNhUmRaruEVFLdkbUg8xMSix0cAWl5D4Jg,9029
21
- tinybird/tb/modules/build.py,sha256=8wzHG_8xrA5D3rjnACTuSeJS4AqFL5rJFzpJnYWCBnQ,8150
22
- tinybird/tb/modules/build_server.py,sha256=6LbJYCSIY6TEEH9DDjZ19pzaAH08roYcWpiP0QNuO6c,2674
21
+ tinybird/tb/modules/build.py,sha256=RRDOd887ym79BWqmLUQxwnjPfG4c4kEGEF2dUP255us,2769
22
+ tinybird/tb/modules/build_client.py,sha256=SoGaGPBYT_0BoRp2lxNyBBvQQ1GFAMpx_o62jb91DUI,8046
23
23
  tinybird/tb/modules/cicd.py,sha256=SjCyvvy0WUnsjFs2biwwXvcf0Ddpmghhd8-SnMyfsRM,5355
24
- tinybird/tb/modules/cli.py,sha256=J3s9RHw1Xwx0q4qUYw0QQGAtjpxhbmKNEFpRiPf4NIU,20844
25
- tinybird/tb/modules/common.py,sha256=W4MyzUAMYl1xRF9bG374NzVjZrz9JCo90MGP5HDBf8o,71529
26
- tinybird/tb/modules/config.py,sha256=fUO-rVPImPnk8DNt0_AUYDlG77eC9Cs2jiVlB9LXCmg,11255
24
+ tinybird/tb/modules/cli.py,sha256=qe1JwNqDVxKdk_vyZ3FWG5wRunGfFdgwQ0NSxUJDYC4,22032
25
+ tinybird/tb/modules/common.py,sha256=e4U7AT0dUBG6O-7Iq2CVN1UHPd6-ZCFucyW0L5gBi4g,70592
26
+ tinybird/tb/modules/config.py,sha256=mie3oMVTf5YOUFEiLs88P16U4LkJafJjSpjwyAkFHog,10979
27
27
  tinybird/tb/modules/connection.py,sha256=FhDM-OAnLN2epbO2YonpjJQhHqBjyuanBsZmKlDXrqg,28679
28
- tinybird/tb/modules/create.py,sha256=kVLEwTfT-SxcF_IWaSh3vVQ5qVPbKQhwVHNO1kzoNyw,10250
29
- tinybird/tb/modules/datasource.py,sha256=Xz2syobLp7SSDFFjCNT90uI8iH-MZ4KC8p7g1SY499Y,32897
30
- tinybird/tb/modules/deploy.py,sha256=95JKtsiIdB9IknNsXTnFlgZgPSkij3zZv2IqLcdn66s,9251
28
+ tinybird/tb/modules/create.py,sha256=Jmx89lgk1jk3rSx2jNzn5Xvr-L8oTetEvr1sEl76Lvw,10846
29
+ tinybird/tb/modules/datasource.py,sha256=PmIoDSLqBNHQvguX9t1T3z9lsG3HB67cmwhQO5_8Lc4,32918
30
+ tinybird/tb/modules/deploy.py,sha256=j1MuiGsWplG1BQs8eG6-STcYyzvHqVESPCOo6P-dcF8,9242
31
31
  tinybird/tb/modules/exceptions.py,sha256=4A2sSjCEqKUMqpP3WI00zouCWW4uLaghXXLZBSw04mY,3363
32
32
  tinybird/tb/modules/feedback_manager.py,sha256=e8tqehRR0Buhs8O0n8N2Sg2vnnBVb1NLtnZqkPrYD_A,68379
33
33
  tinybird/tb/modules/fmt.py,sha256=poh6_cwVGSf-sBu6LKWuO2TANL_J8Sgm25sPpwxa3Aw,3558
34
34
  tinybird/tb/modules/job.py,sha256=956Pj8BEEsiD2GZsV9RKKVM3I_CveOLgS82lykO5ukk,2963
35
- tinybird/tb/modules/llm.py,sha256=yBa_XwWd-iuMMYNg7BZWXxZcwDyW9sfLrcdK81hX6Dk,3215
35
+ tinybird/tb/modules/llm.py,sha256=C6piIQARMnuXA1OmZgngp6f5ehe2qHBunzemRgRQ4KI,3774
36
36
  tinybird/tb/modules/llm_utils.py,sha256=hIfBU7vMUHUt25pljim3WdZdJTNr9hDo3mHezqI5B7w,766
37
- tinybird/tb/modules/local.py,sha256=lHUji6FMhRv4J9sLrHDqyMT-8OwzFSVzDfapnUKS-ZA,5242
37
+ tinybird/tb/modules/local.py,sha256=bSBBk2A0yj4fQHxsdzbZAH1Q_xrqT7vFOIPoz7TNabo,5260
38
38
  tinybird/tb/modules/local_common.py,sha256=fRHJrEix19lAOE4EpzRhWBJH8FUk7hCCvynP0Icf7Ww,2298
39
- tinybird/tb/modules/login.py,sha256=NwpwPQYMVb0mW5-uPR5zb5hl06XqH7xAJfA1GntZzPk,6315
39
+ tinybird/tb/modules/login.py,sha256=0cS-f3MsQFHc6xjw8FRWJm4EJBH9C7Ri68EcO_tiwes,6508
40
40
  tinybird/tb/modules/mock.py,sha256=b0MqSVvJsaXdUKvagXfPGrh-XB8cYmuyXJ2D4P7uyB0,3658
41
41
  tinybird/tb/modules/pipe.py,sha256=eYmMBiSj1Ur_hXUs74YZ9mCSAyiICDmkuKuTemlxPUY,27018
42
42
  tinybird/tb/modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
43
- tinybird/tb/modules/shell.py,sha256=OfFQ4lx3v_XSTr5cm_mTDG6CLc3zFdikM2pOamifG84,13469
43
+ tinybird/tb/modules/shell.py,sha256=Ttb7DHjQoQJKLnVS2VObiIn5UwHOvtPZR2yDtvBF1Cc,13453
44
44
  tinybird/tb/modules/table.py,sha256=4XrtjM-N0zfNtxVkbvLDQQazno1EPXnxTyo7llivfXk,11035
45
45
  tinybird/tb/modules/tag.py,sha256=anPmMUBc-TbFovlpFi8GPkKA18y7Y0GczMsMms5TZsU,3502
46
46
  tinybird/tb/modules/telemetry.py,sha256=iEGnMuCuNhvF6ln__j6X9MSTwL_0Hm-GgFHHHvhfknk,10466
47
- tinybird/tb/modules/test.py,sha256=8rsj8HC9mrldMRx0ViF0XtkF8NHWOsFvQtMTQnJqhpM,10834
47
+ tinybird/tb/modules/test.py,sha256=AQMhVduVg1Oo98Ycla_-49G9nuPxedGwxWyMmkwa0h8,11570
48
48
  tinybird/tb/modules/token.py,sha256=AePr-QMv_vtWwZDWQ92Zp0kPrCjze61i4npiPhoLMZg,12717
49
+ tinybird/tb/modules/update.py,sha256=tQVnFG2yvEDHAwHHkJn_hCw06VBbOgMRJs226_uQjnQ,6813
49
50
  tinybird/tb/modules/watch.py,sha256=9D6NTo9cllyJfvObtOzZEbv3SJN42EgfVdYQPN1liZU,3964
50
51
  tinybird/tb/modules/workspace.py,sha256=6icAgnTvfL3d1kx4L1Z1cGXCD_2Yx0fNRjbZHNxRbYc,10927
51
52
  tinybird/tb/modules/workspace_members.py,sha256=Ai6iCOzXX1zQ8q9iXIFSFHsBJlT-8Q28DaG5Ie-UweY,8726
52
- tinybird/tb/modules/datafile/build.py,sha256=AAyMOkrliBKF0ZPVQBuSx9Qc1D-Y-08sXw90YAg_LiM,57559
53
+ tinybird/tb/modules/datafile/build.py,sha256=pwgsIuvHwb2cdsl3IWOAPyj6S9vB3jn_BXGRcKT7I2Y,57577
53
54
  tinybird/tb/modules/datafile/build_common.py,sha256=IXl-Z51zUi1dypV7meNenX0iu2UmowNeqgG6WHyMHlk,4562
54
55
  tinybird/tb/modules/datafile/build_datasource.py,sha256=4aP8_DYCRGghXntZSeWDNJxjps1QRVa7WHoYCzQwQts,17355
55
- tinybird/tb/modules/datafile/build_pipe.py,sha256=n6jjfBaDl014-jxM5gI9XjUb0XCmgEVoAoAuy_Br8nw,27842
56
+ tinybird/tb/modules/datafile/build_pipe.py,sha256=Jgv3YKIvMfjPiSIdw1k2mpaoDdAWMiMRaSHwRgyI97E,28258
56
57
  tinybird/tb/modules/datafile/common.py,sha256=TSJozXsXzxvkAC_N7dV-Iv_cy2AIGHUNtCYgwlQAbtU,75762
57
58
  tinybird/tb/modules/datafile/diff.py,sha256=-0J7PsBO64T7LOZSkZ4ZFHHCPvT7cKItnJkbz2PkndU,6754
58
59
  tinybird/tb/modules/datafile/exceptions.py,sha256=8rw2umdZjtby85QbuRKFO5ETz_eRHwUY5l7eHsy1wnI,556
@@ -72,8 +73,8 @@ tinybird/tb_cli_modules/config.py,sha256=6u6B5QCdiQLbJkCkwtnKGs9H3nP-KXXhC75mF7B
72
73
  tinybird/tb_cli_modules/exceptions.py,sha256=pmucP4kTF4irIt7dXiG-FcnI-o3mvDusPmch1L8RCWk,3367
73
74
  tinybird/tb_cli_modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
74
75
  tinybird/tb_cli_modules/telemetry.py,sha256=iEGnMuCuNhvF6ln__j6X9MSTwL_0Hm-GgFHHHvhfknk,10466
75
- tinybird-0.0.1.dev28.dist-info/METADATA,sha256=VmwZ1uo4krIPqGkHCGN0_n1eyi5keIbfptaAoHG3B8w,2446
76
- tinybird-0.0.1.dev28.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
77
- tinybird-0.0.1.dev28.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
78
- tinybird-0.0.1.dev28.dist-info/top_level.txt,sha256=pgw6AzERHBcW3YTi2PW4arjxLkulk2msOz_SomfOEuc,45
79
- tinybird-0.0.1.dev28.dist-info/RECORD,,
76
+ tinybird-0.0.1.dev30.dist-info/METADATA,sha256=_ggPTXiep4YjUELu26U3P1pKAz2ieqGakQtVM-NlRhE,2482
77
+ tinybird-0.0.1.dev30.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
78
+ tinybird-0.0.1.dev30.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
79
+ tinybird-0.0.1.dev30.dist-info/top_level.txt,sha256=pgw6AzERHBcW3YTi2PW4arjxLkulk2msOz_SomfOEuc,45
80
+ tinybird-0.0.1.dev30.dist-info/RECORD,,
@@ -1,75 +0,0 @@
1
- import asyncio
2
- import glob
3
- import json
4
- import logging
5
- from pathlib import Path
6
- from typing import List
7
-
8
- import click
9
- import requests
10
-
11
- from tinybird.tb.modules.cli import cli
12
- from tinybird.tb.modules.feedback_manager import FeedbackManager
13
- from tinybird.tb.modules.local_common import get_tinybird_local_client
14
-
15
-
16
- def project_files(project_path: Path) -> List[str]:
17
- project_file_extensions = ("datasource", "pipe")
18
- project_files = []
19
- for extension in project_file_extensions:
20
- for project_file in glob.glob(f"{project_path}/**/*.{extension}", recursive=True):
21
- logging.debug(f"Found project file: {project_file}")
22
- project_files.append(project_file)
23
- return project_files
24
-
25
-
26
- @cli.command()
27
- @click.argument("project_path", type=click.Path(exists=True), default=Path.cwd())
28
- def build_server(project_path: Path) -> None:
29
- """
30
- Validate and build the project server side.
31
- """
32
-
33
- MULTIPART_BOUNDARY_DATA_PROJECT = "data_project://"
34
- DATAFILE_TYPE_TO_CONTENT_TYPE = {
35
- ".datasource": "text/plain",
36
- ".pipe": "text/plain",
37
- }
38
-
39
- tb_client = asyncio.run(get_tinybird_local_client(str(project_path)))
40
- TINYBIRD_API_URL = tb_client.host + "/v1/build"
41
- TINYBIRD_API_KEY = tb_client.token
42
-
43
- files = [
44
- ("context://", ("cli-version", "1.0.0", "text/plain")),
45
- ]
46
- fds = []
47
- for file_path in project_files(project_path):
48
- relative_path = str(Path(file_path).relative_to(project_path))
49
- fd = open(file_path, "rb")
50
- fds.append(fd)
51
- content_type = DATAFILE_TYPE_TO_CONTENT_TYPE.get(Path(file_path).suffix, "application/unknown")
52
- files.append((MULTIPART_BOUNDARY_DATA_PROJECT, (relative_path, fd, content_type)))
53
-
54
- try:
55
- HEADERS = {"Authorization": f"Bearer {TINYBIRD_API_KEY}"}
56
-
57
- r = requests.post(TINYBIRD_API_URL, files=files, headers=HEADERS)
58
- result = r.json()
59
- logging.debug(json.dumps(result, indent=2))
60
-
61
- build_result = result.get("result")
62
- if build_result == "success":
63
- click.echo(FeedbackManager.success(message="Build completed successfully"))
64
- elif build_result == "failed":
65
- click.echo(FeedbackManager.error(message="Build failed"))
66
- build_errors = result.get("errors")
67
- for build_error in build_errors:
68
- click.echo(
69
- FeedbackManager.error(message=f"{build_error.get('filename')}\n\n{build_error.get('error')}")
70
- )
71
- else:
72
- click.echo(FeedbackManager.error(message=f"Unknown build result. Error: {result.get('error')}"))
73
- finally:
74
- for fd in fds:
75
- fd.close()