17
17
# limitations under the License.
18
18
"""Renku ``update`` command."""
19
19
20
- from collections import defaultdict
21
20
from pathlib import Path
22
- from typing import Dict , List , Optional , Set , Tuple
21
+ from typing import Optional
23
22
24
23
from renku .command .command_builder import inject
25
24
from renku .command .command_builder .command import Command
26
25
from renku .command .workflow import execute_workflow
27
26
from renku .core import errors
28
27
from renku .core .errors import ParameterError
29
- from renku .core .interface .activity_gateway import IActivityGateway
30
28
from renku .core .interface .client_dispatcher import IClientDispatcher
31
- from renku .core .interface .plan_gateway import IPlanGateway
32
- from renku .core .util .metadata import add_activity_if_recent , filter_overridden_activities , get_modified_activities
33
29
from renku .core .util .os import get_relative_paths
34
- from renku .core .workflow .activity import sort_activities
30
+ from renku .core .workflow .activity import (
31
+ get_all_modified_and_deleted_activities_and_entities ,
32
+ get_downstream_generating_activities ,
33
+ is_activity_valid ,
34
+ sort_activities ,
35
+ )
35
36
from renku .core .workflow .concrete_execution_graph import ExecutionGraph
36
- from renku .domain_model .provenance .activity import Activity
37
- from renku .domain_model .workflow .plan import AbstractPlan
38
37
39
38
40
39
def update_command ():
@@ -44,10 +43,10 @@ def update_command():
44
43
45
44
@inject .autoparams ()
46
45
def _update (
47
- update_all ,
48
- dry_run ,
46
+ update_all : bool ,
47
+ dry_run : bool ,
48
+ ignore_deleted : bool ,
49
49
client_dispatcher : IClientDispatcher ,
50
- activity_gateway : IActivityGateway ,
51
50
provider : str ,
52
51
config : Optional [str ],
53
52
paths = None ,
@@ -60,10 +59,18 @@ def _update(
60
59
client = client_dispatcher .current_client
61
60
62
61
paths = paths or []
63
- paths = get_relative_paths (base = client .path , paths = paths )
62
+ paths = get_relative_paths (base = client .path , paths = [ Path . cwd () / p for p in paths ] )
64
63
65
- modified_activities , modified_paths = _get_modified_activities_and_paths (client .repository , activity_gateway )
66
- activities = _get_downstream_activities (modified_activities , activity_gateway , paths )
64
+ modified , _ = get_all_modified_and_deleted_activities_and_entities (client .repository )
65
+ modified_activities = {a for a , _ in modified if is_activity_valid (a )}
66
+ modified_paths = {e .path for _ , e in modified }
67
+
68
+ activities = get_downstream_generating_activities (
69
+ starting_activities = modified_activities ,
70
+ paths = paths ,
71
+ ignore_deleted = ignore_deleted ,
72
+ client_path = client .path ,
73
+ )
67
74
68
75
if len (activities ) == 0 :
69
76
raise errors .NothingToExecuteError ()
@@ -75,110 +82,3 @@ def _update(
75
82
76
83
graph = ExecutionGraph ([a .plan_with_values for a in activities ], virtual_links = True )
77
84
execute_workflow (dag = graph .workflow_graph , provider = provider , config = config )
78
-
79
-
80
- @inject .autoparams ()
81
- def _is_activity_valid (activity : Activity , plan_gateway : IPlanGateway , client_dispatcher : IClientDispatcher ) -> bool :
82
- """Return whether this plan is current and has not been deleted.
83
-
84
- Args:
85
- activity(Activity): The Activity whose Plan should be checked.
86
- plan_gateway(IPlanGateway): The injected Plan gateway.
87
- client_dispatcher(IClientDispatcher): The injected client dispatcher.
88
-
89
- Returns:
90
- bool: True if the activities' Plan is still valid, False otherwise.
91
-
92
- """
93
- client = client_dispatcher .current_client
94
-
95
- for usage in activity .usages :
96
- if not (client .path / usage .entity .path ).exists ():
97
- return False
98
-
99
- plan = activity .association .plan
100
-
101
- if plan .invalidated_at is not None :
102
- return False
103
-
104
- # get newest with same name
105
- newest_plan = plan_gateway .get_by_name (plan .name )
106
-
107
- if newest_plan is None or newest_plan .invalidated_at is not None :
108
- return False
109
-
110
- all_plans = plan_gateway .get_all_plans ()
111
-
112
- derived : Optional [AbstractPlan ] = plan
113
- while derived :
114
- plan = derived
115
- derived = next ((p for p in all_plans if p .derived_from is not None and p .derived_from == plan .id ), None )
116
-
117
- return plan .invalidated_at is None
118
-
119
-
120
- def _get_modified_activities_and_paths (repository , activity_gateway ) -> Tuple [Set [Activity ], Set [str ]]:
121
- """Return latest activities that one of their inputs is modified.
122
-
123
- Args:
124
- repository: The current ``Repository``.
125
- activity_gateway: The injected Activity gateway.
126
-
127
- Returns:
128
- Tuple[Set[Activity],Set[str]]: Tuple of modified activites and modified paths.
129
-
130
- """
131
- all_activities = activity_gateway .get_all_activities ()
132
- relevant_activities = filter_overridden_activities (all_activities )
133
- modified , _ = get_modified_activities (activities = list (relevant_activities ), repository = repository )
134
- return {a for a , _ in modified if _is_activity_valid (a )}, {e .path for _ , e in modified }
135
-
136
-
137
- def _get_downstream_activities (
138
- starting_activities : Set [Activity ], activity_gateway : IActivityGateway , paths : List [str ]
139
- ) -> List [Activity ]:
140
- """Return activities downstream of passed activities.
141
-
142
- Args:
143
- starting_activities(Set[Activity]): Activities to use as starting/upstream nodes.
144
- activity_gateway(IActivityGateway): The injected Activity gateway.
145
- paths(List[str]): Optional gnerated paths to end downstream chains at.
146
-
147
- Returns:
148
- Set[Activity]: All activites and their downstream activities.
149
-
150
- """
151
- all_activities : Dict [str , Set [Activity ]] = defaultdict (set )
152
-
153
- def include_newest_activity (activity ):
154
- existing_activities = all_activities [activity .association .plan .id ]
155
- add_activity_if_recent (activity = activity , activities = existing_activities )
156
-
157
- def does_activity_generate_any_paths (activity ):
158
- is_same = any (g .entity .path in paths for g in activity .generations )
159
- is_parent = any (Path (p ) in Path (g .entity .path ).parents for p in paths for g in activity .generations )
160
-
161
- return is_same or is_parent
162
-
163
- for activity in starting_activities :
164
- downstream_chains = activity_gateway .get_downstream_activity_chains (activity )
165
-
166
- if paths :
167
- # NOTE: Add the activity to check if it also matches the condition
168
- downstream_chains .append ((activity ,))
169
- downstream_chains = [c for c in downstream_chains if does_activity_generate_any_paths (c [- 1 ])]
170
-
171
- # NOTE: Include activity only if any of its downstream match the condition
172
- if downstream_chains :
173
- include_newest_activity (activity )
174
- else :
175
- include_newest_activity (activity )
176
-
177
- for chain in downstream_chains :
178
- for activity in chain :
179
- if not _is_activity_valid (activity ):
180
- # don't process further downstream activities as the plan in question was deleted
181
- break
182
- include_newest_activity (activity )
183
-
184
- return list ({a for activities in all_activities .values () for a in activities })
0 commit comments