Coretex
task.py
1 # Copyright (C) 2023 Coretex LLC
2 
3 # This file is part of Coretex.ai
4 
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
9 
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Affero General Public License for more details.
14 
15 # You should have received a copy of the GNU Affero General Public License
16 # along with this program. If not, see <https://www.gnu.org/licenses/>.
17 
18 from typing import Optional
19 
20 import click
21 import webbrowser
22 
23 from ..modules import ui
24 from ..modules.project_utils import getProject
25 from ..modules.user import initializeUserSession
26 from ..modules.utils import onBeforeCommandExecute
27 from ..modules.project_utils import getProject
28 from ..._folder_manager import folder_manager
29 from ..._task import TaskRunWorker, executeRunLocally, readTaskConfig, runLogger
30 from ...configuration import UserConfiguration
31 from ...entities import TaskRun, TaskRunStatus
32 from ...resources import PYTHON_ENTRY_POINT_PATH
33 from ..._task import TaskRunWorker, executeRunLocally, readTaskConfig, runLogger
34 
35 
36 class RunException(Exception):
37  pass
38 
39 
40 @click.command()
41 @click.argument("path", type = click.Path(exists = True, dir_okay = False))
42 @click.option("--name", type = str, default = None)
43 @click.option("--description", type = str, default = None)
44 @click.option("--snapshot", type = bool, default = False)
45 @click.option("--project", "-p", type = str)
46 def run(path: str, name: Optional[str], description: Optional[str], snapshot: bool, project: Optional[str]) -> None:
47  userConfig = UserConfiguration.load()
48 
49  if userConfig.refreshToken is None:
50  raise RunException(f"Failed to execute \"coretex run {path}\" command. Authenticate again using \"coretex login\" command and try again.")
51 
52  parameters = readTaskConfig()
53 
54  # clearing temporary files in case that local run was manually killed before
55  folder_manager.clearTempFiles()
56 
57  selectedProject = getProject(project, userConfig)
58 
59  if selectedProject is None:
60  return
61 
62  ui.stdEcho(
63  "Project info: "
64  f"\n\tName: {selectedProject.name}"
65  f"\n\tProject type: {selectedProject.projectType.name}"
66  f"\n\tDescription: {selectedProject.description}"
67  f"\n\tCreated on: {selectedProject.createdOn}"
68  )
69 
70  taskRun: TaskRun = TaskRun.runLocal(
71  selectedProject.id,
72  snapshot,
73  name,
74  description,
75  [parameter.encode() for parameter in parameters],
76  entryPoint = path
77  )
78 
79  ui.stdEcho(
80  "Task Run successfully started. "
81  f"You can open it by clicking on this URL {ui.outputUrl(userConfig.frontendUrl, taskRun.entityUrl())}."
82  )
83  webbrowser.open(f"{userConfig.frontendUrl}/{taskRun.entityUrl()}")
84 
85  taskRun.updateStatus(TaskRunStatus.preparingToStart)
86 
87  with TaskRunWorker(userConfig.refreshToken, taskRun.id):
88  runLogger.attach(taskRun.id)
89 
90  command = [
91  "python", str(PYTHON_ENTRY_POINT_PATH),
92  "--taskRunId", str(taskRun.id),
93  "--refreshToken", userConfig.refreshToken
94  ]
95 
96  returnCode = executeRunLocally(
97  command,
98  captureErr = True
99  )
100 
101  # Flush logs before updating status to a final one
102  # as that invalidates the auth token
103  runLogger.flushLogs()
104  runLogger.reset()
105 
106  if returnCode != 0:
107  runLogger.fatal(f">> [Coretex] Failed to execute Task. Exit code: {returnCode}")
108  taskRun.updateStatus(TaskRunStatus.completedWithError)
109  else:
110  taskRun.updateStatus(TaskRunStatus.completedWithSuccess)
111 
112  folder_manager.clearTempFiles()
113 
114 
115 @click.group()
116 @onBeforeCommandExecute(initializeUserSession)
117 def task() -> None:
118  pass
119 
120 
121 task.add_command(run, "run")