tinybird 0.0.1.dev152__tar.gz → 0.0.1.dev153__tar.gz
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.
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/PKG-INFO +1 -1
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/__cli__.py +2 -2
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/build.py +38 -9
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/cli.py +1 -1
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/deployment.py +41 -8
- tinybird-0.0.1.dev153/tinybird/tb/modules/dev_server.py +257 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/project.py +2 -1
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird.egg-info/PKG-INFO +1 -1
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird.egg-info/SOURCES.txt +1 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/setup.cfg +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/__cli__.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/ch_utils/constants.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/ch_utils/engine.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/check_pypi.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/client.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/config.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/connectors.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/context.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/datafile.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/datatypes.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/feedback_manager.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/git_settings.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/prompts.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/sql.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/sql_template.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/sql_template_fmt.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/sql_toolset.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/syncasync.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/check_pypi.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/cli.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/client.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/config.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/auth.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/cicd.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/common.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/config.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/connection.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/copy.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/create.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/build.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/build_common.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/common.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/diff.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/exceptions.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/fixture.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/format_common.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/parse_datasource.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/parse_pipe.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/playground.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/pull.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datasource.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/deprecations.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/endpoint.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/exceptions.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/feedback_manager.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/infra.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/job.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/llm.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/llm_utils.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/local.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/local_common.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/login.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/logout.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/materialization.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/mock.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/open.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/pipe.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/regions.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/secret.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/shell.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/table.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/telemetry.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/test.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/token.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/watch.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/workspace.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/workspace_members.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/auth.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/branch.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/cicd.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/cli.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/common.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/config.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/connection.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/datasource.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/exceptions.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/fmt.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/job.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/pipe.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/regions.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/tag.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/telemetry.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/test.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/workspace.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/workspace_members.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tornado_template.py +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird.egg-info/dependency_links.txt +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird.egg-info/entry_points.txt +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird.egg-info/requires.txt +0 -0
- {tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird.egg-info/top_level.txt +0 -0
|
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
|
|
|
4
4
|
__url__ = 'https://www.tinybird.co/docs/cli/introduction.html'
|
|
5
5
|
__author__ = 'Tinybird'
|
|
6
6
|
__author_email__ = 'support@tinybird.co'
|
|
7
|
-
__version__ = '0.0.1.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '0.0.1.dev153'
|
|
8
|
+
__revision__ = '24d7d4a'
|
|
@@ -23,6 +23,7 @@ from tinybird.tb.modules.datafile.fixture import FixtureExtension, get_fixture_d
|
|
|
23
23
|
from tinybird.tb.modules.datafile.parse_datasource import parse_datasource
|
|
24
24
|
from tinybird.tb.modules.datafile.parse_pipe import parse_pipe
|
|
25
25
|
from tinybird.tb.modules.datafile.playground import folder_playground
|
|
26
|
+
from tinybird.tb.modules.dev_server import BuildStatus, start_server
|
|
26
27
|
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
27
28
|
from tinybird.tb.modules.project import Project
|
|
28
29
|
from tinybird.tb.modules.shell import Shell, print_table_formatted
|
|
@@ -50,16 +51,28 @@ def build(ctx: click.Context, watch: bool) -> None:
|
|
|
50
51
|
|
|
51
52
|
@cli.command("dev", help="Build the project server side and watch for changes.")
|
|
52
53
|
@click.option("--data-origin", type=str, default="", help="Data origin: local or cloud")
|
|
54
|
+
@click.option("--ui", is_flag=True, default=False, help="Connect your local project to Tinybird UI")
|
|
53
55
|
@click.pass_context
|
|
54
|
-
def dev(ctx: click.Context, data_origin: str) -> None:
|
|
56
|
+
def dev(ctx: click.Context, data_origin: str, ui: bool) -> None:
|
|
55
57
|
if data_origin == "cloud":
|
|
56
58
|
return dev_cloud(ctx)
|
|
57
|
-
|
|
58
59
|
project: Project = ctx.ensure_object(dict)["project"]
|
|
59
60
|
tb_client: TinyB = ctx.ensure_object(dict)["client"]
|
|
61
|
+
build_status = BuildStatus()
|
|
62
|
+
if ui:
|
|
63
|
+
server_thread = threading.Thread(
|
|
64
|
+
target=start_server, args=(project, tb_client, process, build_status), daemon=True
|
|
65
|
+
)
|
|
66
|
+
server_thread.start()
|
|
67
|
+
# Wait for the server to start
|
|
68
|
+
time.sleep(0.5)
|
|
60
69
|
click.echo(FeedbackManager.highlight_building_project())
|
|
61
|
-
process(project=project, tb_client=tb_client, watch=True)
|
|
62
|
-
run_watch(
|
|
70
|
+
process(project=project, tb_client=tb_client, watch=True, build_status=build_status)
|
|
71
|
+
run_watch(
|
|
72
|
+
project=project,
|
|
73
|
+
tb_client=tb_client,
|
|
74
|
+
process=partial(process, project=project, tb_client=tb_client, build_status=build_status),
|
|
75
|
+
)
|
|
63
76
|
|
|
64
77
|
|
|
65
78
|
def build_project(project: Project, tb_client: TinyB, file_changed: Optional[str] = None, silent: bool = False) -> None:
|
|
@@ -266,10 +279,17 @@ def process(
|
|
|
266
279
|
file_changed: Optional[str] = None,
|
|
267
280
|
diff: Optional[str] = None,
|
|
268
281
|
silent: bool = False,
|
|
269
|
-
|
|
282
|
+
error: bool = False,
|
|
283
|
+
build_status: Optional[BuildStatus] = None,
|
|
284
|
+
) -> Optional[str]:
|
|
270
285
|
time_start = time.time()
|
|
271
286
|
build_failed = False
|
|
272
287
|
build_error: Optional[str] = None
|
|
288
|
+
if build_status:
|
|
289
|
+
if build_status.building:
|
|
290
|
+
return build_status.error
|
|
291
|
+
else:
|
|
292
|
+
build_status.building = True
|
|
273
293
|
if file_changed and (file_changed.endswith(FixtureExtension.NDJSON) or file_changed.endswith(FixtureExtension.CSV)):
|
|
274
294
|
rebuild_fixture(project, tb_client, file_changed)
|
|
275
295
|
elif file_changed and file_changed.endswith(".sql"):
|
|
@@ -277,6 +297,9 @@ def process(
|
|
|
277
297
|
else:
|
|
278
298
|
try:
|
|
279
299
|
build_project(project, tb_client, file_changed, silent)
|
|
300
|
+
if build_status:
|
|
301
|
+
build_status.building = False
|
|
302
|
+
build_status.error = None
|
|
280
303
|
except click.ClickException as e:
|
|
281
304
|
click.echo(FeedbackManager.info(message=str(e)))
|
|
282
305
|
build_error = str(e)
|
|
@@ -284,7 +307,8 @@ def process(
|
|
|
284
307
|
try:
|
|
285
308
|
if file_changed and not build_failed:
|
|
286
309
|
asyncio.run(folder_build(project, tb_client, filenames=[file_changed]))
|
|
287
|
-
|
|
310
|
+
if not build_status:
|
|
311
|
+
show_data(tb_client, file_changed, diff)
|
|
288
312
|
except Exception:
|
|
289
313
|
pass
|
|
290
314
|
|
|
@@ -296,14 +320,19 @@ def process(
|
|
|
296
320
|
click.echo(FeedbackManager.error(message=f"✗ {rebuild_str} failed"))
|
|
297
321
|
if not watch:
|
|
298
322
|
sys_exit("build_error", build_error or "Unknown error")
|
|
323
|
+
build_error = build_error or "Unknown error"
|
|
324
|
+
if build_status:
|
|
325
|
+
build_status.error = build_error
|
|
326
|
+
build_status.building = False
|
|
327
|
+
return build_error
|
|
299
328
|
else:
|
|
300
329
|
if not silent:
|
|
301
330
|
click.echo(FeedbackManager.success(message=f"\n✓ {rebuild_str} completed in {elapsed_time:.1f}s"))
|
|
302
331
|
|
|
332
|
+
return None
|
|
303
333
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
) -> None:
|
|
334
|
+
|
|
335
|
+
def run_watch(project: Project, tb_client: TinyB, process: Callable) -> None:
|
|
307
336
|
shell = Shell(project=project, tb_client=tb_client, playground=False)
|
|
308
337
|
click.echo(FeedbackManager.gray(message="\nWatching for changes..."))
|
|
309
338
|
watcher_thread = threading.Thread(
|
|
@@ -141,7 +141,7 @@ async def cli(
|
|
|
141
141
|
config = await get_config(host, token, user_token=user_token, config_file=config_temp._path)
|
|
142
142
|
client = _get_tb_client(config.get("token", None), config["host"])
|
|
143
143
|
folder = os.path.join(config_temp._path.replace(".tinyb", ""), config.get("cwd", os.getcwd()))
|
|
144
|
-
project = Project(folder=folder)
|
|
144
|
+
project = Project(folder=folder, workspace_name=config.get("name", ""))
|
|
145
145
|
config["path"] = str(project.path)
|
|
146
146
|
# If they have passed a token or host as parameter and it's different that record in .tinyb, refresh the workspace id
|
|
147
147
|
if token or host:
|
|
@@ -68,7 +68,6 @@ def download_github_template(url: str) -> Optional[Path]:
|
|
|
68
68
|
"""
|
|
69
69
|
# Parse GitHub URL components
|
|
70
70
|
# From: https://github.com/owner/repo/tree/branch/path
|
|
71
|
-
# To: api.github.com/repos/owner/repo/contents/path?ref=branch
|
|
72
71
|
parts = url.replace("https://github.com/", "").split("/")
|
|
73
72
|
if len(parts) < 5 or "tree" not in parts:
|
|
74
73
|
click.echo(
|
|
@@ -83,16 +82,50 @@ def download_github_template(url: str) -> Optional[Path]:
|
|
|
83
82
|
branch = parts[parts.index("tree") + 1]
|
|
84
83
|
path = "/".join(parts[parts.index("tree") + 2 :])
|
|
85
84
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
try:
|
|
86
|
+
import shutil
|
|
87
|
+
import subprocess
|
|
88
|
+
import tempfile
|
|
89
|
+
|
|
90
|
+
# Create a temporary directory for cloning
|
|
91
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
92
|
+
# Clone the specific branch with minimum depth
|
|
93
|
+
repo_url = f"https://github.com/{owner}/{repo}.git"
|
|
94
|
+
subprocess.run(
|
|
95
|
+
["git", "clone", "--depth", "1", "--branch", branch, repo_url, temp_dir],
|
|
96
|
+
check=True,
|
|
97
|
+
capture_output=True,
|
|
98
|
+
)
|
|
89
99
|
|
|
90
|
-
|
|
100
|
+
# Copy the specific path to current directory
|
|
101
|
+
source_path = Path(temp_dir) / path
|
|
102
|
+
if not source_path.exists():
|
|
103
|
+
click.echo(FeedbackManager.error(message=f"Path {path} not found in repository"))
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
dir = Path(".")
|
|
107
|
+
if source_path.is_dir():
|
|
108
|
+
# Copy directory contents
|
|
109
|
+
for item in source_path.iterdir():
|
|
110
|
+
dest = dir / item.name
|
|
111
|
+
if item.is_dir():
|
|
112
|
+
shutil.copytree(item, dest)
|
|
113
|
+
else:
|
|
114
|
+
shutil.copy2(item, dest)
|
|
115
|
+
click.echo(FeedbackManager.info(message=f"Downloaded {item.name}"))
|
|
116
|
+
else:
|
|
117
|
+
# Copy single file
|
|
118
|
+
shutil.copy2(source_path, dir / source_path.name)
|
|
119
|
+
click.echo(FeedbackManager.info(message=f"Downloaded {source_path.name}"))
|
|
91
120
|
|
|
92
|
-
|
|
93
|
-
download_github_contents(api_url, dir)
|
|
121
|
+
return dir
|
|
94
122
|
|
|
95
|
-
|
|
123
|
+
except subprocess.CalledProcessError as e:
|
|
124
|
+
click.echo(FeedbackManager.error(message=f"Git clone failed: {e.stderr.decode()}"))
|
|
125
|
+
return None
|
|
126
|
+
except Exception as e:
|
|
127
|
+
click.echo(FeedbackManager.error(message=f"Error downloading template: {str(e)}"))
|
|
128
|
+
return None
|
|
96
129
|
|
|
97
130
|
|
|
98
131
|
# TODO(eclbg): This should eventually end up in client.py, but we're not using it here yet.
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import glob
|
|
2
|
+
import http.server
|
|
3
|
+
import json
|
|
4
|
+
import time
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Callable, Optional
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
|
|
10
|
+
from tinybird.tb.client import TinyB
|
|
11
|
+
from tinybird.tb.modules.common import sys_exit
|
|
12
|
+
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
13
|
+
from tinybird.tb.modules.local_common import TB_LOCAL_PORT
|
|
14
|
+
from tinybird.tb.modules.project import Project
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class BuildStatus:
|
|
18
|
+
def __init__(self):
|
|
19
|
+
self.last_build_time = 0
|
|
20
|
+
self.building = False
|
|
21
|
+
self.error: Optional[str] = None
|
|
22
|
+
self.result: Optional[str] = None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class DevServer(http.server.HTTPServer):
|
|
26
|
+
project: Project
|
|
27
|
+
tb_client: TinyB
|
|
28
|
+
process: Callable
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
process: Callable,
|
|
33
|
+
project: Project,
|
|
34
|
+
build_status: BuildStatus,
|
|
35
|
+
tb_client: TinyB,
|
|
36
|
+
):
|
|
37
|
+
port = 49161
|
|
38
|
+
self.project = project
|
|
39
|
+
self.tb_client = tb_client
|
|
40
|
+
self.process = process
|
|
41
|
+
self.build_status = build_status
|
|
42
|
+
self.port = port
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
super().__init__(("", port), DevHandler)
|
|
46
|
+
click.echo(FeedbackManager.success(message=f"✓ Dev server running on http://localhost:{port}"))
|
|
47
|
+
click.echo(
|
|
48
|
+
FeedbackManager.info(
|
|
49
|
+
message=f"* Access your project at https://cloud.tinybird.co/local/{TB_LOCAL_PORT}/{project.workspace_name}/project"
|
|
50
|
+
)
|
|
51
|
+
)
|
|
52
|
+
except OSError as e:
|
|
53
|
+
if e.errno == 48: # Address already in use
|
|
54
|
+
click.echo(FeedbackManager.error(message=f"Port {port} is already in use. Try a different port."))
|
|
55
|
+
sys_exit("port_in_use", f"Port {port} is already in use")
|
|
56
|
+
else:
|
|
57
|
+
click.echo(FeedbackManager.error_exception(error=e))
|
|
58
|
+
sys_exit("server_error", str(e))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class DevHandler(http.server.SimpleHTTPRequestHandler):
|
|
62
|
+
server: DevServer
|
|
63
|
+
|
|
64
|
+
def send_cors_headers(self):
|
|
65
|
+
self.send_header("Access-Control-Allow-Origin", "*")
|
|
66
|
+
self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
|
67
|
+
self.send_header("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
|
68
|
+
|
|
69
|
+
def do_OPTIONS(self):
|
|
70
|
+
self.send_response(200)
|
|
71
|
+
self.send_cors_headers()
|
|
72
|
+
self.end_headers()
|
|
73
|
+
|
|
74
|
+
def do_GET(self):
|
|
75
|
+
try:
|
|
76
|
+
project: Project = self.server.project
|
|
77
|
+
|
|
78
|
+
if self.path == "/":
|
|
79
|
+
self.send_response(200)
|
|
80
|
+
self.send_header("Content-Type", "text/html")
|
|
81
|
+
self.send_cors_headers()
|
|
82
|
+
self.end_headers()
|
|
83
|
+
|
|
84
|
+
html = f"""
|
|
85
|
+
<!DOCTYPE html>
|
|
86
|
+
<html>
|
|
87
|
+
<head>
|
|
88
|
+
<title>Tinybird Dev Server</title>
|
|
89
|
+
<style>
|
|
90
|
+
body {{ font-family: Arial, sans-serif; margin: 40px; line-height: 1.6; }}
|
|
91
|
+
h1 {{ color: #333; }}
|
|
92
|
+
ul {{ list-style-type: none; padding: 0; }}
|
|
93
|
+
li {{ margin-bottom: 10px; }}
|
|
94
|
+
a {{ color: #0066cc; text-decoration: none; }}
|
|
95
|
+
a:hover {{ text-decoration: underline; }}
|
|
96
|
+
</style>
|
|
97
|
+
</head>
|
|
98
|
+
<body>
|
|
99
|
+
<h1>Tinybird Dev Server</h1>
|
|
100
|
+
<p>Server running for project: {project.path}</p>
|
|
101
|
+
<p>Access your local environment at <a href="https://cloud.tinybird.co/local/{TB_LOCAL_PORT}/{project.workspace_name}/project">https://cloud.tinybird.co/local/{TB_LOCAL_PORT}/{project.workspace_name}/project</a> and edit your project.</p>
|
|
102
|
+
<h2>API Endpoints:</h2>
|
|
103
|
+
<ul>
|
|
104
|
+
<li><a href="/files">/files</a> - List all project files</li>
|
|
105
|
+
</ul>
|
|
106
|
+
</body>
|
|
107
|
+
</html>
|
|
108
|
+
"""
|
|
109
|
+
self.wfile.write(html.encode())
|
|
110
|
+
return
|
|
111
|
+
|
|
112
|
+
elif "/files/" in self.path:
|
|
113
|
+
file_path = self.path.split("/files/")[1].split("?")[0]
|
|
114
|
+
project_files = project.get_project_files()
|
|
115
|
+
project_file = next((Path(f) for f in project_files if f.endswith(file_path)), None)
|
|
116
|
+
if not project_file:
|
|
117
|
+
self.send_response(404)
|
|
118
|
+
self.send_header("Content-Type", "application/json")
|
|
119
|
+
self.send_cors_headers()
|
|
120
|
+
self.end_headers()
|
|
121
|
+
self.wfile.write(json.dumps({"status": "error", "error": "Resource not found"}).encode())
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
self.send_response(200)
|
|
125
|
+
self.send_header("Content-Type", "application/json")
|
|
126
|
+
self.send_cors_headers()
|
|
127
|
+
self.end_headers()
|
|
128
|
+
self.wfile.write(json.dumps({"path": str(project_file), "content": project_file.read_text()}).encode())
|
|
129
|
+
return
|
|
130
|
+
|
|
131
|
+
elif "/files" in self.path:
|
|
132
|
+
project_files = project.get_project_files()
|
|
133
|
+
self.send_response(200)
|
|
134
|
+
self.send_header("Content-Type", "application/json")
|
|
135
|
+
self.send_cors_headers()
|
|
136
|
+
self.end_headers()
|
|
137
|
+
self.wfile.write(
|
|
138
|
+
json.dumps(
|
|
139
|
+
{
|
|
140
|
+
"files": [f.replace(f"{project.folder}/", "") for f in project_files],
|
|
141
|
+
"root": project.folder,
|
|
142
|
+
"workspace_name": project.workspace_name,
|
|
143
|
+
}
|
|
144
|
+
).encode()
|
|
145
|
+
)
|
|
146
|
+
return
|
|
147
|
+
|
|
148
|
+
# Handle all other paths
|
|
149
|
+
self.send_response(404)
|
|
150
|
+
self.send_header("Content-Type", "application/json")
|
|
151
|
+
self.send_cors_headers()
|
|
152
|
+
self.end_headers()
|
|
153
|
+
self.wfile.write(json.dumps({"status": "error", "message": "Not found"}).encode())
|
|
154
|
+
|
|
155
|
+
except Exception as e:
|
|
156
|
+
self.send_response(400)
|
|
157
|
+
self.send_header("Content-Type", "application/json")
|
|
158
|
+
self.send_cors_headers()
|
|
159
|
+
self.end_headers()
|
|
160
|
+
self.wfile.write(json.dumps({"status": "error", "message": str(e)}).encode())
|
|
161
|
+
|
|
162
|
+
def do_POST(self):
|
|
163
|
+
try:
|
|
164
|
+
# Parse the request body
|
|
165
|
+
content_length = int(self.headers["Content-Length"])
|
|
166
|
+
body = self.rfile.read(content_length)
|
|
167
|
+
data = json.loads(body)
|
|
168
|
+
|
|
169
|
+
# Get the file path from the request body
|
|
170
|
+
file_path = data.get("path")
|
|
171
|
+
if not file_path:
|
|
172
|
+
self.send_response(400)
|
|
173
|
+
self.send_header("Content-Type", "application/json")
|
|
174
|
+
self.send_cors_headers()
|
|
175
|
+
self.end_headers()
|
|
176
|
+
self.wfile.write(json.dumps({"status": "error", "message": "No file path provided"}).encode())
|
|
177
|
+
return
|
|
178
|
+
|
|
179
|
+
exists = glob.glob(f"{self.server.project.folder}/**/{file_path}", recursive=True)
|
|
180
|
+
if not exists:
|
|
181
|
+
self.send_response(400)
|
|
182
|
+
self.send_header("Content-Type", "application/json")
|
|
183
|
+
self.send_cors_headers()
|
|
184
|
+
self.end_headers()
|
|
185
|
+
self.wfile.write(json.dumps({"status": "error", "message": "File does not exist"}).encode())
|
|
186
|
+
return
|
|
187
|
+
|
|
188
|
+
# Get the content from the request body
|
|
189
|
+
content = data.get("content")
|
|
190
|
+
if not content:
|
|
191
|
+
self.send_response(400)
|
|
192
|
+
self.send_header("Content-Type", "application/json")
|
|
193
|
+
self.send_cors_headers()
|
|
194
|
+
self.end_headers()
|
|
195
|
+
self.wfile.write(json.dumps({"status": "error", "message": "No content provided"}).encode())
|
|
196
|
+
return
|
|
197
|
+
|
|
198
|
+
# Write the content to the file
|
|
199
|
+
file_path = exists[0]
|
|
200
|
+
with open(file_path, "w") as f:
|
|
201
|
+
f.write(content)
|
|
202
|
+
# sleep for 0.2 seconds to ensure the file is written
|
|
203
|
+
time.sleep(0.2)
|
|
204
|
+
|
|
205
|
+
def check_build_status(attempts: int = 0):
|
|
206
|
+
if attempts > 10:
|
|
207
|
+
return "Build timeout. Check the console for more details."
|
|
208
|
+
if self.server.build_status.building:
|
|
209
|
+
time.sleep(0.5)
|
|
210
|
+
return check_build_status(attempts + 1)
|
|
211
|
+
else:
|
|
212
|
+
return self.server.build_status.error
|
|
213
|
+
|
|
214
|
+
build_error = check_build_status()
|
|
215
|
+
if build_error:
|
|
216
|
+
raise Exception(build_error)
|
|
217
|
+
|
|
218
|
+
self.send_response(200)
|
|
219
|
+
self.send_header("Content-Type", "application/json")
|
|
220
|
+
self.send_cors_headers()
|
|
221
|
+
self.end_headers()
|
|
222
|
+
self.wfile.write(json.dumps({"status": "success", "message": "File written successfully"}).encode())
|
|
223
|
+
|
|
224
|
+
except Exception as e:
|
|
225
|
+
self.send_response(400)
|
|
226
|
+
self.send_header("Content-Type", "application/json")
|
|
227
|
+
self.send_cors_headers()
|
|
228
|
+
self.end_headers()
|
|
229
|
+
self.wfile.write(json.dumps({"status": "error", "error": str(e)}).encode())
|
|
230
|
+
|
|
231
|
+
def log_message(self, format, *args):
|
|
232
|
+
pass
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def start_server(project: Project, tb_client: TinyB, process: Callable, build_status: BuildStatus):
|
|
236
|
+
"""Start a development server for the project.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
project: The project instance to serve.
|
|
240
|
+
"""
|
|
241
|
+
|
|
242
|
+
try:
|
|
243
|
+
click.echo(FeedbackManager.highlight(message="\n» Starting Tinybird dev server...\n"))
|
|
244
|
+
|
|
245
|
+
# Create and start the server
|
|
246
|
+
server = DevServer(process, project, build_status, tb_client)
|
|
247
|
+
server.serve_forever()
|
|
248
|
+
|
|
249
|
+
# Run the server in the main thread
|
|
250
|
+
click.echo(FeedbackManager.gray(message="\nWatching for changes...\n"))
|
|
251
|
+
click.echo(FeedbackManager.highlight(message="Press Ctrl+C to stop the server\n"))
|
|
252
|
+
|
|
253
|
+
except KeyboardInterrupt:
|
|
254
|
+
click.echo(FeedbackManager.highlight(message="\n» Stopping Tinybird dev server...\n"))
|
|
255
|
+
except Exception as e:
|
|
256
|
+
click.echo(FeedbackManager.error_exception(error=e))
|
|
257
|
+
sys_exit("server_error", str(e))
|
|
@@ -11,8 +11,9 @@ from tinybird.tb.modules.datafile.parse_pipe import parse_pipe
|
|
|
11
11
|
class Project:
|
|
12
12
|
extensions = ("datasource", "pipe", "connection")
|
|
13
13
|
|
|
14
|
-
def __init__(self, folder: str):
|
|
14
|
+
def __init__(self, folder: str, workspace_name: str):
|
|
15
15
|
self.folder = folder
|
|
16
|
+
self.workspace_name = workspace_name
|
|
16
17
|
|
|
17
18
|
@property
|
|
18
19
|
def path(self) -> Path:
|
|
@@ -41,6 +41,7 @@ tinybird/tb/modules/create.py
|
|
|
41
41
|
tinybird/tb/modules/datasource.py
|
|
42
42
|
tinybird/tb/modules/deployment.py
|
|
43
43
|
tinybird/tb/modules/deprecations.py
|
|
44
|
+
tinybird/tb/modules/dev_server.py
|
|
44
45
|
tinybird/tb/modules/endpoint.py
|
|
45
46
|
tinybird/tb/modules/exceptions.py
|
|
46
47
|
tinybird/tb/modules/feedback_manager.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/build_common.py
RENAMED
|
File without changes
|
{tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/build_datasource.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/format_common.py
RENAMED
|
File without changes
|
{tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/format_datasource.py
RENAMED
|
File without changes
|
|
File without changes
|
{tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/parse_datasource.py
RENAMED
|
File without changes
|
|
File without changes
|
{tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/datafile/pipe_checker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb/modules/tinyunit/tinyunit_lib.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/tinyunit/tinyunit.py
RENAMED
|
File without changes
|
{tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py
RENAMED
|
File without changes
|
|
File without changes
|
{tinybird-0.0.1.dev152 → tinybird-0.0.1.dev153}/tinybird/tb_cli_modules/workspace_members.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|