bundlewrap 5.1.0__tar.gz → 5.2.0__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.
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/CHANGELOG.md +9 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/PKG-INFO +1 -1
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/__init__.py +1 -1
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/parser.py +4 -2
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/directories.py +14 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/node.py +33 -26
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/repo.py +13 -6
- bundlewrap-5.2.0/bundlewrap/utils/node_lambda.py +34 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap.egg-info/PKG-INFO +1 -1
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/setup.py +1 -1
- bundlewrap-5.1.0/bundlewrap/utils/node_lambda.py +0 -55
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/AUTHORS +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/LICENSE +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/MANIFEST.in +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/README.md +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/bundle.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/__init__.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/apply.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/debug.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/diff.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/generate_completions.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/groups.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/hash.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/ipmi.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/items.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/lock.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/metadata.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/nodes.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/plot.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/pw.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/repo.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/run.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/stats.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/test.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/verify.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/cmdline/zen.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/concurrency.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/deps.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/exceptions.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/group.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/itemqueue.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/__init__.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/actions.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/dconf.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/files.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/git_deploy.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/groups.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/kubernetes.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/pkg.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/pkg_apk.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/pkg_apt.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/pkg_dnf.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/pkg_freebsd.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/pkg_openbsd.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/pkg_opkg.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/pkg_pacman.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/pkg_pamac.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/pkg_pip.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/pkg_snap.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/pkg_yum.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/pkg_zypper.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/postgres_dbs.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/postgres_roles.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/routeros.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/svc_freebsd.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/svc_openbsd.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/svc_openrc.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/svc_systemd.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/svc_systemv.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/symlinks.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/users.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/zfs_dataset.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/items/zfs_pool.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/lock.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/metadata.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/metagen.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/operations.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/secrets.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/utils/__init__.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/utils/cmdline.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/utils/crypto.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/utils/dicts.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/utils/magic_strings.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/utils/metastack.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/utils/plot.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/utils/remote.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/utils/scm.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/utils/table.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/utils/testing.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/utils/text.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap/utils/ui.py +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap.egg-info/SOURCES.txt +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap.egg-info/dependency_links.txt +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap.egg-info/entry_points.txt +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap.egg-info/not-zip-safe +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap.egg-info/requires.txt +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/bundlewrap.egg-info/top_level.txt +0 -0
- {bundlewrap-5.1.0 → bundlewrap-5.2.0}/setup.cfg +0 -0
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
# 5.2.0
|
|
2
|
+
|
|
3
|
+
2026-10-07
|
|
4
|
+
|
|
5
|
+
* added `$BW_LOCK_ADD_SKIP_ITEM_VERIFICATION`: This sets a default for the `--skip-item-verification` option of `bw lock`
|
|
6
|
+
* `bw verify` will skip items when Faults are unavailable (instead of showing long stack traces), now matches the behavior of `bw apply`
|
|
7
|
+
* added `pre_purge_command` to `directory` items
|
|
8
|
+
* fixed `repo.nodes_matching()`: No longer swallows errors and now raises `NoSuchTarget` as documented
|
|
9
|
+
|
|
1
10
|
# 5.1.0
|
|
2
11
|
|
|
3
12
|
2026-06-18
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
VERSION = (5,
|
|
1
|
+
VERSION = (5, 2, 0)
|
|
2
2
|
VERSION_STRING = ".".join([str(v) for v in VERSION])
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
from argparse import ArgumentParser,
|
|
1
|
+
from argparse import (ArgumentParser, BooleanOptionalAction,
|
|
2
|
+
RawTextHelpFormatter, SUPPRESS)
|
|
2
3
|
from os import environ, getcwd
|
|
3
4
|
from os.path import join
|
|
4
5
|
|
|
@@ -581,7 +582,8 @@ bundle:my_bundle # items in this bundle
|
|
|
581
582
|
)
|
|
582
583
|
parser_lock_add.add_argument(
|
|
583
584
|
"--skip-item-verification",
|
|
584
|
-
action=
|
|
585
|
+
action=BooleanOptionalAction,
|
|
586
|
+
default=bool(int(environ.get('BW_LOCK_ADD_SKIP_ITEM_VERIFICATION', 0))),
|
|
585
587
|
dest='skip_item_verification',
|
|
586
588
|
help=_("disable verification of item selector (-i)"),
|
|
587
589
|
)
|
|
@@ -49,6 +49,7 @@ class Directory(Item):
|
|
|
49
49
|
'mode': "0755",
|
|
50
50
|
'owner': "root",
|
|
51
51
|
'purge': False,
|
|
52
|
+
'pre_purge_command': None,
|
|
52
53
|
}
|
|
53
54
|
ITEM_TYPE_NAME = "directory"
|
|
54
55
|
|
|
@@ -98,6 +99,11 @@ class Directory(Item):
|
|
|
98
99
|
return
|
|
99
100
|
|
|
100
101
|
for path in status.actual_state.get('paths_to_purge', set()):
|
|
102
|
+
if self.attributes['pre_purge_command']:
|
|
103
|
+
self.run(self.attributes['pre_purge_command'].format(
|
|
104
|
+
path=quote(path),
|
|
105
|
+
file=quote(path.split('/')[-1]),
|
|
106
|
+
))
|
|
101
107
|
self.run("rm -rf -- {}".format(quote(path)))
|
|
102
108
|
|
|
103
109
|
for fix_type in ('mode', 'owner', 'group'):
|
|
@@ -280,6 +286,14 @@ class Directory(Item):
|
|
|
280
286
|
for key, value in attributes.items():
|
|
281
287
|
ATTRIBUTE_VALIDATORS[key](item_id, value)
|
|
282
288
|
|
|
289
|
+
if attributes.get('pre_purge_command') and not attributes.get('purge'):
|
|
290
|
+
raise BundleError(_(
|
|
291
|
+
"{b} {i} cannot use pre_purge_command if not purging"
|
|
292
|
+
).format(
|
|
293
|
+
n=bundle.name,
|
|
294
|
+
i=item_id,
|
|
295
|
+
))
|
|
296
|
+
|
|
283
297
|
@classmethod
|
|
284
298
|
def validate_name(cls, bundle, name):
|
|
285
299
|
if normpath(name) != name:
|
|
@@ -13,6 +13,7 @@ from .concurrency import WorkerPool
|
|
|
13
13
|
from .deps import find_item, ItemDependencyLoop
|
|
14
14
|
from .exceptions import (
|
|
15
15
|
BundleError,
|
|
16
|
+
FaultUnavailable,
|
|
16
17
|
GracefulApplyException,
|
|
17
18
|
ItemSkipped,
|
|
18
19
|
NodeLockedException,
|
|
@@ -1145,38 +1146,44 @@ def verify_items(
|
|
|
1145
1146
|
return bool(items)
|
|
1146
1147
|
|
|
1147
1148
|
def next_task():
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
item=item.id,
|
|
1161
|
-
msg=yellow(_("Fault unavailable")),
|
|
1162
|
-
node=bold(node.name),
|
|
1163
|
-
x=yellow("»"),
|
|
1164
|
-
))
|
|
1165
|
-
else:
|
|
1166
|
-
return {
|
|
1167
|
-
'task_id': node.name + ":" + item.bundle.name + ":" + item.id,
|
|
1168
|
-
'target': item.verify,
|
|
1169
|
-
'kwargs': {
|
|
1170
|
-
'autoskip_selector': autoskip_selector,
|
|
1171
|
-
'autoonly_selector': autoonly_selector,
|
|
1172
|
-
},
|
|
1173
|
-
}
|
|
1149
|
+
try:
|
|
1150
|
+
item = items.pop()
|
|
1151
|
+
except IndexError:
|
|
1152
|
+
return None
|
|
1153
|
+
return {
|
|
1154
|
+
'task_id': node.name + ":" + item.bundle.name + ":" + item.id,
|
|
1155
|
+
'target': item.verify,
|
|
1156
|
+
'kwargs': {
|
|
1157
|
+
'autoskip_selector': autoskip_selector,
|
|
1158
|
+
'autoonly_selector': autoonly_selector,
|
|
1159
|
+
},
|
|
1160
|
+
}
|
|
1174
1161
|
|
|
1175
1162
|
def handle_exception(task_id, exception, traceback):
|
|
1176
1163
|
node_name, bundle_name, item_id = task_id.split(":", 2)
|
|
1177
1164
|
io.progress_advance()
|
|
1178
1165
|
if isinstance(exception, (ItemSkipped, NotImplementedError)):
|
|
1179
1166
|
pass
|
|
1167
|
+
elif isinstance(exception, FaultUnavailable):
|
|
1168
|
+
item = node.get_item(item_id)
|
|
1169
|
+
if item.error_on_missing_fault:
|
|
1170
|
+
io.stderr(_("{x} {node} {bundle} {item} ({msg})").format(
|
|
1171
|
+
bundle=bold(bundle_name),
|
|
1172
|
+
item=item_id,
|
|
1173
|
+
msg=red(_("Fault unavailable")),
|
|
1174
|
+
node=bold(node_name),
|
|
1175
|
+
x=red("!"),
|
|
1176
|
+
))
|
|
1177
|
+
return False
|
|
1178
|
+
else:
|
|
1179
|
+
io.stdout(_("{x} {node} {bundle} {item} ({msg})").format(
|
|
1180
|
+
bundle=bold(bundle_name),
|
|
1181
|
+
item=item_id,
|
|
1182
|
+
msg=yellow(_("Fault unavailable")),
|
|
1183
|
+
node=bold(node_name),
|
|
1184
|
+
x=yellow("»"),
|
|
1185
|
+
))
|
|
1186
|
+
return None
|
|
1180
1187
|
else:
|
|
1181
1188
|
# Unlike with `bw apply`, it is OK for `bw verify` to encounter
|
|
1182
1189
|
# exceptions when getting an item's status. `bw verify` doesn't
|
|
@@ -696,28 +696,35 @@ class Repository(MetadataGenerator):
|
|
|
696
696
|
targets = set()
|
|
697
697
|
for name in target_strings:
|
|
698
698
|
name = name.strip()
|
|
699
|
+
targets_for_name = set()
|
|
699
700
|
if name.startswith("bundle:"):
|
|
700
701
|
bundle_name = name.split(":", 1)[1]
|
|
701
|
-
|
|
702
|
+
targets_for_name.update(self.nodes_with_bundle(bundle_name))
|
|
702
703
|
elif name.startswith("!bundle:"):
|
|
703
704
|
bundle_name = name.split(":", 1)[1]
|
|
704
|
-
|
|
705
|
+
targets_for_name.update(self.nodes_without_bundle(bundle_name))
|
|
705
706
|
elif name.startswith("!group:"):
|
|
706
707
|
group_name = name.split(":", 1)[1]
|
|
707
|
-
|
|
708
|
+
targets_for_name.update(self.nodes_not_in_group(group_name))
|
|
708
709
|
elif name.startswith("lambda:"):
|
|
709
710
|
lambda_str = name.split(":", 1)[1]
|
|
710
|
-
|
|
711
|
+
targets_for_name.update(self.nodes_matching_lambda(lambda_str, lambda_workers))
|
|
711
712
|
else:
|
|
712
713
|
try:
|
|
713
|
-
|
|
714
|
+
targets_for_name.add(self.get_node(name))
|
|
714
715
|
except NoSuchNode:
|
|
715
716
|
try:
|
|
716
717
|
group = self.get_group(name)
|
|
717
|
-
|
|
718
|
+
targets_for_name.update(group.nodes)
|
|
718
719
|
except NoSuchGroup:
|
|
719
720
|
raise NoSuchTarget(name)
|
|
720
721
|
|
|
722
|
+
# Puplic API docs demand this.
|
|
723
|
+
if not targets_for_name:
|
|
724
|
+
raise NoSuchTarget(name)
|
|
725
|
+
|
|
726
|
+
targets |= targets_for_name
|
|
727
|
+
|
|
721
728
|
return list(targets)
|
|
722
729
|
|
|
723
730
|
def metadata_hash(self):
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from bundlewrap.concurrency import WorkerPool
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def parallel_node_eval(
|
|
5
|
+
nodes,
|
|
6
|
+
expression,
|
|
7
|
+
workers,
|
|
8
|
+
):
|
|
9
|
+
nodes = set(nodes)
|
|
10
|
+
|
|
11
|
+
def tasks_available():
|
|
12
|
+
return bool(nodes)
|
|
13
|
+
|
|
14
|
+
def next_task():
|
|
15
|
+
node = nodes.pop()
|
|
16
|
+
|
|
17
|
+
def get_values():
|
|
18
|
+
return eval("lambda node: " + expression)(node)
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
'task_id': node.name,
|
|
22
|
+
'target': get_values,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
def handle_result(task_id, result, _duration):
|
|
26
|
+
return task_id, result
|
|
27
|
+
|
|
28
|
+
worker_pool = WorkerPool(
|
|
29
|
+
tasks_available,
|
|
30
|
+
next_task,
|
|
31
|
+
handle_result=handle_result,
|
|
32
|
+
workers=workers,
|
|
33
|
+
)
|
|
34
|
+
return dict(worker_pool.run())
|
|
@@ -2,7 +2,7 @@ from setuptools import find_packages, setup
|
|
|
2
2
|
|
|
3
3
|
setup(
|
|
4
4
|
name="bundlewrap",
|
|
5
|
-
version="5.
|
|
5
|
+
version="5.2.0",
|
|
6
6
|
description="Config management with Python",
|
|
7
7
|
long_description=(
|
|
8
8
|
"By allowing for easy and low-overhead config management, BundleWrap fills the gap between complex deployments using Chef or Puppet and old school system administration over SSH.\n"
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
from traceback import format_exc
|
|
2
|
-
|
|
3
|
-
from bundlewrap.concurrency import WorkerPool
|
|
4
|
-
from bundlewrap.exceptions import RepositoryError
|
|
5
|
-
from bundlewrap.utils.text import red, bold, prefix_lines, _
|
|
6
|
-
from bundlewrap.utils.ui import io
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def parallel_node_eval(
|
|
10
|
-
nodes,
|
|
11
|
-
expression,
|
|
12
|
-
workers,
|
|
13
|
-
):
|
|
14
|
-
nodes = set(nodes)
|
|
15
|
-
|
|
16
|
-
def tasks_available():
|
|
17
|
-
return bool(nodes)
|
|
18
|
-
|
|
19
|
-
def next_task():
|
|
20
|
-
node = nodes.pop()
|
|
21
|
-
|
|
22
|
-
def get_values():
|
|
23
|
-
try:
|
|
24
|
-
return eval("lambda node: " + expression)(node)
|
|
25
|
-
except RepositoryError:
|
|
26
|
-
raise
|
|
27
|
-
except Exception:
|
|
28
|
-
traceback = format_exc()
|
|
29
|
-
io.stderr(_(
|
|
30
|
-
"{x} {node} Exception while evaluating `{expression}`, returning as None:\n{traceback}"
|
|
31
|
-
).format(
|
|
32
|
-
x=red("✘"),
|
|
33
|
-
node=bold(node),
|
|
34
|
-
expression=expression,
|
|
35
|
-
traceback=prefix_lines("\n" + traceback, f"{red('│')} ") + red("╵"),
|
|
36
|
-
))
|
|
37
|
-
# Returning None here is kinda meh. But it's the only alternative
|
|
38
|
-
# to failing hard by re-raising, which would be very annoying.
|
|
39
|
-
return None
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
'task_id': node.name,
|
|
43
|
-
'target': get_values,
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
def handle_result(task_id, result, _duration):
|
|
47
|
-
return task_id, result
|
|
48
|
-
|
|
49
|
-
worker_pool = WorkerPool(
|
|
50
|
-
tasks_available,
|
|
51
|
-
next_task,
|
|
52
|
-
handle_result=handle_result,
|
|
53
|
-
workers=workers,
|
|
54
|
-
)
|
|
55
|
-
return dict(worker_pool.run())
|
|
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
|
|
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
|
|
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
|