fractal-server 2.14.16__py3-none-any.whl → 2.15.0a1__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.
Files changed (41) hide show
  1. fractal_server/__init__.py +1 -1
  2. fractal_server/app/models/v2/task_group.py +17 -5
  3. fractal_server/app/routes/admin/v2/task_group_lifecycle.py +2 -2
  4. fractal_server/app/routes/api/v2/__init__.py +6 -0
  5. fractal_server/app/routes/api/v2/task_collection.py +3 -3
  6. fractal_server/app/routes/api/v2/task_collection_custom.py +2 -2
  7. fractal_server/app/routes/api/v2/task_collection_pixi.py +236 -0
  8. fractal_server/app/routes/api/v2/task_group_lifecycle.py +26 -7
  9. fractal_server/app/schemas/v2/__init__.py +2 -1
  10. fractal_server/app/schemas/v2/dumps.py +1 -1
  11. fractal_server/app/schemas/v2/task_collection.py +1 -1
  12. fractal_server/app/schemas/v2/task_group.py +16 -5
  13. fractal_server/config.py +42 -0
  14. fractal_server/migrations/versions/b1e7f7a1ff71_task_group_for_pixi.py +53 -0
  15. fractal_server/ssh/_fabric.py +26 -0
  16. fractal_server/tasks/v2/local/__init__.py +3 -0
  17. fractal_server/tasks/v2/local/_utils.py +7 -2
  18. fractal_server/tasks/v2/local/collect.py +23 -24
  19. fractal_server/tasks/v2/local/collect_pixi.py +234 -0
  20. fractal_server/tasks/v2/local/deactivate.py +36 -39
  21. fractal_server/tasks/v2/local/deactivate_pixi.py +102 -0
  22. fractal_server/tasks/v2/local/reactivate.py +9 -16
  23. fractal_server/tasks/v2/local/reactivate_pixi.py +146 -0
  24. fractal_server/tasks/v2/ssh/__init__.py +3 -0
  25. fractal_server/tasks/v2/ssh/_utils.py +5 -5
  26. fractal_server/tasks/v2/ssh/collect.py +23 -28
  27. fractal_server/tasks/v2/ssh/collect_pixi.py +306 -0
  28. fractal_server/tasks/v2/ssh/deactivate.py +39 -45
  29. fractal_server/tasks/v2/ssh/deactivate_pixi.py +128 -0
  30. fractal_server/tasks/v2/ssh/reactivate.py +8 -15
  31. fractal_server/tasks/v2/ssh/reactivate_pixi.py +108 -0
  32. fractal_server/tasks/v2/templates/pixi_1_extract.sh +40 -0
  33. fractal_server/tasks/v2/templates/pixi_2_install.sh +48 -0
  34. fractal_server/tasks/v2/templates/pixi_3_post_install.sh +80 -0
  35. fractal_server/tasks/v2/utils_background.py +43 -8
  36. fractal_server/tasks/v2/utils_pixi.py +38 -0
  37. {fractal_server-2.14.16.dist-info → fractal_server-2.15.0a1.dist-info}/METADATA +1 -1
  38. {fractal_server-2.14.16.dist-info → fractal_server-2.15.0a1.dist-info}/RECORD +41 -29
  39. {fractal_server-2.14.16.dist-info → fractal_server-2.15.0a1.dist-info}/LICENSE +0 -0
  40. {fractal_server-2.14.16.dist-info → fractal_server-2.15.0a1.dist-info}/WHEEL +0 -0
  41. {fractal_server-2.14.16.dist-info → fractal_server-2.15.0a1.dist-info}/entry_points.txt +0 -0
@@ -1,16 +1,14 @@
1
- import logging
2
1
  import time
3
2
  from pathlib import Path
4
3
  from tempfile import TemporaryDirectory
5
4
 
6
5
  from ..utils_background import add_commit_refresh
7
6
  from ..utils_background import fail_and_cleanup
7
+ from ..utils_background import get_activity_and_task_group
8
8
  from ..utils_templates import get_collection_replacements
9
9
  from ._utils import _copy_wheel_file_ssh
10
10
  from ._utils import _customize_and_run_template
11
11
  from fractal_server.app.db import get_sync_db
12
- from fractal_server.app.models.v2 import TaskGroupActivityV2
13
- from fractal_server.app.models.v2 import TaskGroupV2
14
12
  from fractal_server.app.schemas.v2 import TaskGroupActivityActionV2
15
13
  from fractal_server.app.schemas.v2 import TaskGroupV2OriginEnum
16
14
  from fractal_server.app.schemas.v2.task_group import TaskGroupActivityStatusV2
@@ -61,17 +59,12 @@ def deactivate_ssh(
61
59
  ) as fractal_ssh:
62
60
 
63
61
  with next(get_sync_db()) as db:
64
-
65
- # Get main objects from db
66
- activity = db.get(TaskGroupActivityV2, task_group_activity_id)
67
- task_group = db.get(TaskGroupV2, task_group_id)
68
- if activity is None or task_group is None:
69
- # Use `logging` directly
70
- logging.error(
71
- "Cannot find database rows with "
72
- f"{task_group_id=} and {task_group_activity_id=}:\n"
73
- f"{task_group=}\n{activity=}. Exit."
74
- )
62
+ success, task_group, activity = get_activity_and_task_group(
63
+ task_group_activity_id=task_group_activity_id,
64
+ task_group_id=task_group_id,
65
+ db=db,
66
+ )
67
+ if not success:
75
68
  return
76
69
 
77
70
  # Log some info
@@ -113,10 +106,10 @@ def deactivate_ssh(
113
106
  activity.status = TaskGroupActivityStatusV2.ONGOING
114
107
  activity = add_commit_refresh(obj=activity, db=db)
115
108
 
116
- if task_group.pip_freeze is None:
109
+ if task_group.env_info is None:
117
110
  logger.warning(
118
111
  "Recreate pip-freeze information, since "
119
- f"{task_group.pip_freeze=}. NOTE: this should "
112
+ f"{task_group.env_info=}. NOTE: this should "
120
113
  "only happen for task groups created before 2.9.0."
121
114
  )
122
115
 
@@ -161,7 +154,7 @@ def deactivate_ssh(
161
154
  )
162
155
  activity.log = get_current_log(log_file_path)
163
156
  activity = add_commit_refresh(obj=activity, db=db)
164
- task_group.pip_freeze = pip_freeze_stdout
157
+ task_group.env_info = pip_freeze_stdout
165
158
  task_group = add_commit_refresh(obj=task_group, db=db)
166
159
  logger.info(
167
160
  "Add pip freeze stdout to TaskGroupV2 - end"
@@ -174,18 +167,19 @@ def deactivate_ssh(
174
167
  f"Handle specific cases for {task_group.origin=}."
175
168
  )
176
169
 
177
- # Blocking situation: `wheel_path` is not set or points
178
- # to a missing path
170
+ # Blocking situation: `archive_path` is not set or
171
+ # points to a missing path
179
172
  if (
180
- task_group.wheel_path is None
173
+ task_group.archive_path is None
181
174
  or not fractal_ssh.remote_exists(
182
- task_group.wheel_path
175
+ task_group.archive_path
183
176
  )
184
177
  ):
185
178
  error_msg = (
186
179
  "Invalid wheel path for task group with "
187
- f"{task_group_id=}. {task_group.wheel_path=} "
188
- "is unset or does not exist."
180
+ f"{task_group_id=}. "
181
+ f"{task_group.archive_path=} is unset or "
182
+ "does not exist."
189
183
  )
190
184
  logger.error(error_msg)
191
185
  fail_and_cleanup(
@@ -198,58 +192,58 @@ def deactivate_ssh(
198
192
  )
199
193
  return
200
194
 
201
- # Recoverable situation: `wheel_path` was not yet
195
+ # Recoverable situation: `archive_path` was not yet
202
196
  # copied over to the correct server-side folder
203
- wheel_path_parent_dir = Path(
204
- task_group.wheel_path
197
+ archive_path_parent_dir = Path(
198
+ task_group.archive_path
205
199
  ).parent
206
- if wheel_path_parent_dir != Path(task_group.path):
200
+ if archive_path_parent_dir != Path(task_group.path):
207
201
  logger.warning(
208
- f"{wheel_path_parent_dir.as_posix()} differs "
209
- f"from {task_group.path}. NOTE: this should "
210
- "only happen for task groups created before "
211
- "2.9.0."
202
+ f"{archive_path_parent_dir.as_posix()} "
203
+ f"differs from {task_group.path}. "
204
+ "NOTE: this should only happen for task "
205
+ "groups created before 2.9.0."
212
206
  )
213
207
 
214
208
  if (
215
- task_group.wheel_path
216
- not in task_group.pip_freeze
209
+ task_group.archive_path
210
+ not in task_group.env_info
217
211
  ):
218
212
  raise ValueError(
219
- f"Cannot find {task_group.wheel_path=} in "
220
- "pip-freeze data. Exit."
213
+ f"Cannot find {task_group.archive_path=} "
214
+ "in pip-freeze data. Exit."
221
215
  )
222
216
 
223
217
  logger.info(
224
218
  f"Now copy wheel file into {task_group.path}."
225
219
  )
226
- new_wheel_path = _copy_wheel_file_ssh(
220
+ new_archive_path = _copy_wheel_file_ssh(
227
221
  task_group=task_group,
228
222
  fractal_ssh=fractal_ssh,
229
223
  logger_name=LOGGER_NAME,
230
224
  )
231
225
  logger.info(
232
- f"Copied wheel file to {new_wheel_path}."
226
+ f"Copied wheel file to {new_archive_path}."
233
227
  )
234
228
 
235
- task_group.wheel_path = new_wheel_path
236
- new_pip_freeze = task_group.pip_freeze.replace(
237
- task_group.wheel_path,
238
- new_wheel_path,
229
+ task_group.archive_path = new_archive_path
230
+ new_pip_freeze = task_group.env_info.replace(
231
+ task_group.archive_path,
232
+ new_archive_path,
239
233
  )
240
- task_group.pip_freeze = new_pip_freeze
234
+ task_group.env_info = new_pip_freeze
241
235
  task_group = add_commit_refresh(
242
236
  obj=task_group, db=db
243
237
  )
244
238
  logger.info(
245
- "Updated `wheel_path` and `pip_freeze` "
239
+ "Updated `archive_path` and `env_info` "
246
240
  "task-group attributes."
247
241
  )
248
242
 
249
- # Fail if `pip_freeze` includes "github", see
243
+ # Fail if `env_info` includes "github", see
250
244
  # https://github.com/fractal-analytics-platform/fractal-server/issues/2142
251
245
  for forbidden_string in FORBIDDEN_DEPENDENCY_STRINGS:
252
- if forbidden_string in task_group.pip_freeze:
246
+ if forbidden_string in task_group.env_info:
253
247
  raise ValueError(
254
248
  "Deactivation and reactivation of task "
255
249
  f"packages with direct {forbidden_string} "
@@ -0,0 +1,128 @@
1
+ from pathlib import Path
2
+ from tempfile import TemporaryDirectory
3
+
4
+ from ..utils_background import add_commit_refresh
5
+ from ..utils_background import fail_and_cleanup
6
+ from ..utils_background import get_activity_and_task_group
7
+ from ..utils_pixi import SOURCE_DIR_NAME
8
+ from fractal_server.app.db import get_sync_db
9
+ from fractal_server.app.schemas.v2.task_group import TaskGroupActivityStatusV2
10
+ from fractal_server.logger import reset_logger_handlers
11
+ from fractal_server.logger import set_logger
12
+ from fractal_server.ssh._fabric import SingleUseFractalSSH
13
+ from fractal_server.ssh._fabric import SSHConfig
14
+ from fractal_server.tasks.utils import get_log_path
15
+ from fractal_server.tasks.v2.utils_background import get_current_log
16
+ from fractal_server.utils import get_timestamp
17
+
18
+
19
+ def deactivate_ssh_pixi(
20
+ *,
21
+ task_group_activity_id: int,
22
+ task_group_id: int,
23
+ ssh_config: SSHConfig,
24
+ tasks_base_dir: str,
25
+ ) -> None:
26
+ """
27
+ Deactivate a pixi task group venv.
28
+
29
+ This function is run as a background task, therefore exceptions must be
30
+ handled.
31
+
32
+ Arguments:
33
+ task_group_id:
34
+ task_group_activity_id:
35
+ ssh_config:
36
+ tasks_base_dir:
37
+ Only used as a `safe_root` in `remove_dir`, and typically set to
38
+ `user_settings.ssh_tasks_dir`.
39
+ """
40
+
41
+ LOGGER_NAME = f"{__name__}.ID{task_group_activity_id}"
42
+
43
+ with TemporaryDirectory() as tmpdir:
44
+ log_file_path = get_log_path(Path(tmpdir))
45
+ logger = set_logger(
46
+ logger_name=LOGGER_NAME,
47
+ log_file_path=log_file_path,
48
+ )
49
+ with SingleUseFractalSSH(
50
+ ssh_config=ssh_config,
51
+ logger_name=LOGGER_NAME,
52
+ ) as fractal_ssh:
53
+
54
+ with next(get_sync_db()) as db:
55
+ success, task_group, activity = get_activity_and_task_group(
56
+ task_group_activity_id=task_group_activity_id,
57
+ task_group_id=task_group_id,
58
+ db=db,
59
+ )
60
+ if not success:
61
+ return
62
+
63
+ # Log some info
64
+ logger.debug("START")
65
+ for key, value in task_group.model_dump().items():
66
+ logger.debug(f"task_group.{key}: {value}")
67
+
68
+ # Check that SSH connection works
69
+ try:
70
+ fractal_ssh.check_connection()
71
+ except Exception as e:
72
+ logger.error("Cannot establish SSH connection.")
73
+ fail_and_cleanup(
74
+ task_group=task_group,
75
+ task_group_activity=activity,
76
+ logger_name=LOGGER_NAME,
77
+ log_file_path=log_file_path,
78
+ exception=e,
79
+ db=db,
80
+ )
81
+ return
82
+
83
+ try:
84
+ # Check that the (remote) task_group venv_path does exist
85
+ source_dir = Path(
86
+ task_group.path, SOURCE_DIR_NAME
87
+ ).as_posix()
88
+ if not fractal_ssh.remote_exists(source_dir):
89
+ error_msg = f"{source_dir} does not exist."
90
+ logger.error(error_msg)
91
+ fail_and_cleanup(
92
+ task_group=task_group,
93
+ task_group_activity=activity,
94
+ logger_name=LOGGER_NAME,
95
+ log_file_path=log_file_path,
96
+ exception=FileNotFoundError(error_msg),
97
+ db=db,
98
+ )
99
+ return
100
+
101
+ # Actually mark the task group as non-active
102
+ logger.info("Now setting `active=False`.")
103
+ task_group.active = False
104
+ task_group = add_commit_refresh(obj=task_group, db=db)
105
+
106
+ # Proceed with deactivation
107
+ logger.info(f"Now removing {source_dir}.")
108
+ fractal_ssh.remove_folder(
109
+ folder=source_dir,
110
+ safe_root=tasks_base_dir,
111
+ )
112
+ logger.info(f"All good, {source_dir} removed.")
113
+ activity.status = TaskGroupActivityStatusV2.OK
114
+ activity.log = get_current_log(log_file_path)
115
+ activity.timestamp_ended = get_timestamp()
116
+ activity = add_commit_refresh(obj=activity, db=db)
117
+
118
+ reset_logger_handlers(logger)
119
+
120
+ except Exception as e:
121
+ fail_and_cleanup(
122
+ task_group=task_group,
123
+ task_group_activity=activity,
124
+ logger_name=LOGGER_NAME,
125
+ log_file_path=log_file_path,
126
+ exception=e,
127
+ db=db,
128
+ )
@@ -1,15 +1,13 @@
1
- import logging
2
1
  import time
3
2
  from pathlib import Path
4
3
  from tempfile import TemporaryDirectory
5
4
 
6
5
  from ..utils_background import add_commit_refresh
7
6
  from ..utils_background import fail_and_cleanup
7
+ from ..utils_background import get_activity_and_task_group
8
8
  from ..utils_templates import get_collection_replacements
9
9
  from ._utils import _customize_and_run_template
10
10
  from fractal_server.app.db import get_sync_db
11
- from fractal_server.app.models.v2 import TaskGroupActivityV2
12
- from fractal_server.app.models.v2 import TaskGroupV2
13
11
  from fractal_server.app.schemas.v2 import TaskGroupActivityActionV2
14
12
  from fractal_server.app.schemas.v2.task_group import TaskGroupActivityStatusV2
15
13
  from fractal_server.logger import reset_logger_handlers
@@ -62,17 +60,12 @@ def reactivate_ssh(
62
60
  ) as fractal_ssh:
63
61
 
64
62
  with next(get_sync_db()) as db:
65
-
66
- # Get main objects from db
67
- activity = db.get(TaskGroupActivityV2, task_group_activity_id)
68
- task_group = db.get(TaskGroupV2, task_group_id)
69
- if activity is None or task_group is None:
70
- # Use `logging` directly
71
- logging.error(
72
- "Cannot find database rows with "
73
- f"{task_group_id=} and {task_group_activity_id=}:\n"
74
- f"{task_group=}\n{activity=}. Exit."
75
- )
63
+ success, task_group, activity = get_activity_and_task_group(
64
+ task_group_activity_id=task_group_activity_id,
65
+ task_group_id=task_group_id,
66
+ db=db,
67
+ )
68
+ if not success:
76
69
  return
77
70
 
78
71
  # Log some info
@@ -128,7 +121,7 @@ def reactivate_ssh(
128
121
  Path(task_group.path) / "_tmp_pip_freeze.txt"
129
122
  ).as_posix()
130
123
  with open(pip_freeze_file_local, "w") as f:
131
- f.write(task_group.pip_freeze)
124
+ f.write(task_group.env_info)
132
125
  fractal_ssh.send_file(
133
126
  local=pip_freeze_file_local,
134
127
  remote=pip_freeze_file_remote,
@@ -0,0 +1,108 @@
1
+ from pathlib import Path
2
+ from tempfile import TemporaryDirectory
3
+
4
+ from ..utils_background import fail_and_cleanup
5
+ from ..utils_background import get_activity_and_task_group
6
+ from fractal_server.app.db import get_sync_db
7
+ from fractal_server.logger import reset_logger_handlers
8
+ from fractal_server.logger import set_logger
9
+ from fractal_server.ssh._fabric import SingleUseFractalSSH
10
+ from fractal_server.ssh._fabric import SSHConfig
11
+ from fractal_server.tasks.utils import get_log_path
12
+
13
+
14
+ def reactivate_ssh_pixi(
15
+ *,
16
+ task_group_activity_id: int,
17
+ task_group_id: int,
18
+ ssh_config: SSHConfig,
19
+ tasks_base_dir: str,
20
+ ) -> None:
21
+ """
22
+ Reactivate a task group venv.
23
+
24
+ This function is run as a background task, therefore exceptions must be
25
+ handled.
26
+
27
+ Arguments:
28
+ task_group_id:
29
+ task_group_activity_id:
30
+ ssh_config:
31
+ tasks_base_dir:
32
+ Only used as a `safe_root` in `remove_dir`, and typically set to
33
+ `user_settings.ssh_tasks_dir`.
34
+ """
35
+
36
+ LOGGER_NAME = f"{__name__}.ID{task_group_activity_id}"
37
+
38
+ with TemporaryDirectory() as tmpdir:
39
+ log_file_path = get_log_path(Path(tmpdir))
40
+ logger = set_logger(
41
+ logger_name=LOGGER_NAME,
42
+ log_file_path=log_file_path,
43
+ )
44
+
45
+ with SingleUseFractalSSH(
46
+ ssh_config=ssh_config,
47
+ logger_name=LOGGER_NAME,
48
+ ) as fractal_ssh:
49
+
50
+ with next(get_sync_db()) as db:
51
+ success, task_group, activity = get_activity_and_task_group(
52
+ task_group_activity_id=task_group_activity_id,
53
+ task_group_id=task_group_id,
54
+ db=db,
55
+ )
56
+ if not success:
57
+ return
58
+
59
+ # Log some info
60
+ logger.info("START")
61
+ for key, value in task_group.model_dump().items():
62
+ logger.debug(f"task_group.{key}: {value}")
63
+
64
+ # Check that SSH connection works
65
+ try:
66
+ fractal_ssh.check_connection()
67
+ except Exception as e:
68
+ logger.error("Cannot establish SSH connection.")
69
+ fail_and_cleanup(
70
+ task_group=task_group,
71
+ task_group_activity=activity,
72
+ logger_name=LOGGER_NAME,
73
+ log_file_path=log_file_path,
74
+ exception=e,
75
+ db=db,
76
+ )
77
+ return
78
+
79
+ try:
80
+ raise NotImplementedError("pixi-task reactivation FIXME")
81
+
82
+ reset_logger_handlers(logger)
83
+
84
+ except Exception as reactivate_e:
85
+ # Delete corrupted venv_path
86
+ try:
87
+ logger.info(
88
+ f"Now delete folder {task_group.venv_path}"
89
+ )
90
+ fractal_ssh.remove_folder(
91
+ folder=task_group.venv_path,
92
+ safe_root=tasks_base_dir,
93
+ )
94
+ logger.info(f"Deleted folder {task_group.venv_path}")
95
+ except Exception as rm_e:
96
+ logger.error(
97
+ "Removing folder failed.\n"
98
+ f"Original error:\n{str(rm_e)}"
99
+ )
100
+
101
+ fail_and_cleanup(
102
+ task_group=task_group,
103
+ task_group_activity=activity,
104
+ logger_name=LOGGER_NAME,
105
+ log_file_path=log_file_path,
106
+ exception=reactivate_e,
107
+ db=db,
108
+ )
@@ -0,0 +1,40 @@
1
+ set -e
2
+
3
+ write_log(){
4
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
5
+ echo "[collect-task-pixi, ${TIMESTAMP}] ${1}"
6
+ }
7
+
8
+ # Replacements
9
+ PACKAGE_DIR="__PACKAGE_DIR__"
10
+ TAR_GZ_PATH="__TAR_GZ_PATH__"
11
+ SOURCE_DIR_NAME="__SOURCE_DIR_NAME__"
12
+
13
+ # Strip trailing `/` from `PACKAGE_DIR`
14
+ PACKAGE_DIR=${PACKAGE_DIR%/}
15
+
16
+ # Known paths
17
+ SOURCE_DIR="${PACKAGE_DIR}/${SOURCE_DIR_NAME}"
18
+ TAR_GZ_BASENAME=$(basename "${TAR_GZ_PATH}" ".tar.gz")
19
+
20
+ TIME_START=$(date +%s)
21
+
22
+ cd "${PACKAGE_DIR}"
23
+ write_log "Changed working directory to ${PACKAGE_DIR}"
24
+
25
+ # -----------------------------------------------------------------------------
26
+
27
+ write_log "START 'tar xz -f ${TAR_GZ_PATH} ${TAR_GZ_BASENAME}'"
28
+ tar xz -f "${TAR_GZ_PATH}" "${TAR_GZ_BASENAME}"
29
+ write_log "END 'tar xz -f ${TAR_GZ_PATH} ${TAR_GZ_BASENAME}'"
30
+ echo
31
+
32
+ write_log "START 'mv ${PACKAGE_DIR}/${TAR_GZ_BASENAME} ${SOURCE_DIR}'"
33
+ mv "${PACKAGE_DIR}/${TAR_GZ_BASENAME}" "${SOURCE_DIR}"
34
+ write_log "END 'mv ${PACKAGE_DIR}/${TAR_GZ_BASENAME} ${SOURCE_DIR}'"
35
+ echo
36
+
37
+ TIME_END=$(date +%s)
38
+ write_log "Elapsed: $((TIME_END - TIME_START)) seconds"
39
+ write_log "All ok, exit."
40
+ echo
@@ -0,0 +1,48 @@
1
+ set -e
2
+
3
+ write_log(){
4
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
5
+ echo "[collect-task-pixi, ${TIMESTAMP}] ${1}"
6
+ }
7
+
8
+ # Replacements
9
+ PIXI_HOME="__PIXI_HOME__"
10
+ PACKAGE_DIR="__PACKAGE_DIR__"
11
+ SOURCE_DIR_NAME="__SOURCE_DIR_NAME__"
12
+ FROZEN_OPTION="__FROZEN_OPTION__"
13
+
14
+ # Strip trailing `/` from `PACKAGE_DIR`
15
+ PIXI_HOME=${PIXI_HOME%/}
16
+ PACKAGE_DIR=${PACKAGE_DIR%/}
17
+
18
+ # Known paths
19
+ PIXI_EXECUTABLE="${PIXI_HOME}/bin/pixi"
20
+ SOURCE_DIR="${PACKAGE_DIR}/${SOURCE_DIR_NAME}"
21
+ PYPROJECT_TOML="${SOURCE_DIR}/pyproject.toml"
22
+
23
+ # Pixi env variable
24
+ export PIXI_HOME="${PIXI_HOME}"
25
+ export PIXI_CACHE_DIR="${PIXI_HOME}/cache"
26
+ export RATTLER_AUTH_FILE="${PIXI_HOME}/credentials.json"
27
+
28
+ TIME_START=$(date +%s)
29
+
30
+ cd "${PACKAGE_DIR}"
31
+ write_log "Changed working directory to ${PACKAGE_DIR}"
32
+
33
+ # -----------------------------------------------------------------------------
34
+
35
+ FROZEN_FLAG=""
36
+ if [[ "${FROZEN_OPTION}" == "true" ]]; then
37
+ FROZEN_FLAG="--frozen"
38
+ fi
39
+
40
+ write_log "START '${PIXI_EXECUTABLE} install ${FROZEN_FLAG} --manifest-path ${PYPROJECT_TOML}'"
41
+ ${PIXI_EXECUTABLE} install ${FROZEN_FLAG} --manifest-path "${PYPROJECT_TOML}"
42
+ write_log "END '${PIXI_EXECUTABLE} install ${FROZEN_FLAG} --manifest-path ${PYPROJECT_TOML}'"
43
+ echo
44
+
45
+ TIME_END=$(date +%s)
46
+ write_log "Elapsed: $((TIME_END - TIME_START)) seconds"
47
+ write_log "All ok, exit."
48
+ echo
@@ -0,0 +1,80 @@
1
+ set -e
2
+
3
+ write_log(){
4
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
5
+ echo "[collect-task-pixi, ${TIMESTAMP}] ${1}"
6
+ }
7
+
8
+ # Replacements
9
+ PIXI_HOME="__PIXI_HOME__"
10
+ PACKAGE_DIR="__PACKAGE_DIR__"
11
+ SOURCE_DIR_NAME="__SOURCE_DIR_NAME__"
12
+ IMPORT_PACKAGE_NAME="__IMPORT_PACKAGE_NAME__"
13
+
14
+ # Strip trailing `/` from `PACKAGE_DIR`
15
+ PIXI_HOME=${PIXI_HOME%/}
16
+ PACKAGE_DIR=${PACKAGE_DIR%/}
17
+
18
+ # Known paths
19
+ PIXI_EXECUTABLE="${PIXI_HOME}/bin/pixi"
20
+ SOURCE_DIR="${PACKAGE_DIR}/${SOURCE_DIR_NAME}"
21
+ PYPROJECT_TOML="${SOURCE_DIR}/pyproject.toml"
22
+ ACTIVATION_FILE="${SOURCE_DIR}/activate_project.sh"
23
+ PROJECT_PYTHON_WRAPPER="${SOURCE_DIR}/project_python.sh"
24
+
25
+ # Pixi env variable
26
+ export PIXI_HOME="${PIXI_HOME}"
27
+ export PIXI_CACHE_DIR="${PIXI_HOME}/cache"
28
+ export RATTLER_AUTH_FILE="${PIXI_HOME}/credentials.json"
29
+
30
+
31
+ TIME_START=$(date +%s)
32
+
33
+ cd "${PACKAGE_DIR}"
34
+ write_log "Changed working directory to ${PACKAGE_DIR}"
35
+
36
+ # -----------------------------------------------------------------------------
37
+
38
+ write_log "START '${PIXI_EXECUTABLE} shell-hook --manifest-path ${PYPROJECT_TOML}'"
39
+ ${PIXI_EXECUTABLE} shell-hook --manifest-path "${PYPROJECT_TOML}" > "${ACTIVATION_FILE}"
40
+ write_log "END '${PIXI_EXECUTABLE} shell-hook --manifest-path ${PYPROJECT_TOML}'"
41
+ echo
42
+
43
+ PROJECT_PYTHON_BIN=$(${PIXI_EXECUTABLE} run --manifest-path "${PYPROJECT_TOML}" which python)
44
+ write_log "Found PROJECT_PYTHON_BIN=${PROJECT_PYTHON_BIN}"
45
+
46
+ # Write project-scoped Python wrapper
47
+ cat <<EOF > "${PROJECT_PYTHON_WRAPPER}"
48
+ #!/bin/bash
49
+ source ${ACTIVATION_FILE}
50
+ ${PROJECT_PYTHON_BIN} "\$@"
51
+ EOF
52
+
53
+ chmod 755 "${PROJECT_PYTHON_WRAPPER}"
54
+ write_log "Written ${PROJECT_PYTHON_WRAPPER} with 755 permissions"
55
+ write_log "Project Python wrapper: ${PROJECT_PYTHON_WRAPPER}"
56
+ write_log "Project-Python version: $(${PROJECT_PYTHON_WRAPPER} --version)"
57
+ echo
58
+
59
+ # Find PACKAGE_FOLDER
60
+ FIND_PACKAGE_FOLDER_SCRIPT="${SOURCE_DIR}/find_package_folder.sh"
61
+ echo "source ${ACTIVATION_FILE}" > "${FIND_PACKAGE_FOLDER_SCRIPT}"
62
+ echo "${PROJECT_PYTHON_BIN} -c \"import ${IMPORT_PACKAGE_NAME} as p, os; print(os.path.dirname(p.__file__))\"" >> "${FIND_PACKAGE_FOLDER_SCRIPT}"
63
+ PACKAGE_FOLDER=$(bash "${FIND_PACKAGE_FOLDER_SCRIPT}")
64
+ write_log "Package folder: ${PACKAGE_FOLDER}"
65
+ echo
66
+
67
+ ENV_DISK_USAGE=$(du -sk "${PACKAGE_DIR}" | cut -f1)
68
+ ENV_FILE_NUMBER=$(find "${PACKAGE_DIR}" -type f | wc -l)
69
+ write_log "Disk usage: ${ENV_DISK_USAGE}"
70
+ write_log "Number of files: ${ENV_FILE_NUMBER}"
71
+ echo
72
+
73
+ write_log "START chmod 755 ${SOURCE_DIR} -R"
74
+ chmod 755 "${SOURCE_DIR}" -R
75
+ write_log "END chmod 755 ${SOURCE_DIR} -R"
76
+
77
+ TIME_END=$(date +%s)
78
+ write_log "Elapsed: $((TIME_END - TIME_START)) seconds"
79
+ write_log "All ok, exit."
80
+ echo