dv-flow-mgr 0.0.1.12761553329a1__py3-none-any.whl → 0.0.1.12822558956a1__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.
dv_flow_mgr/fileset.py CHANGED
@@ -24,8 +24,9 @@ from pydantic import BaseModel
24
24
  from typing import Any, Dict, List, Tuple
25
25
 
26
26
  class FileSet(BaseModel):
27
- src : str
28
27
  type : str
29
28
  basedir : str
29
+ name : str = ""
30
+ src : str = None
30
31
  files : List[str] = dc.Field(default_factory=list)
31
32
  params : Dict[str,str] = dc.Field(default_factory=dict)
dv_flow_mgr/task.py CHANGED
@@ -155,14 +155,6 @@ class Task(object):
155
155
  # Merge filesets. A fileset with the same
156
156
  print("deps_o: %s" % str(deps_o))
157
157
 
158
- # First, merge the dep maps of all the inputs
159
- deps_m = self.depends[0].output.deps.copy()
160
- for deps in map(lambda d: d.deps, self.depends[1:]):
161
- for k,v in deps.items():
162
- if k in deps_m:
163
- deps_m[k].add(v)
164
- else:
165
- deps_m[k] = set(v)
166
158
 
167
159
  print("deps_m: %s" % str(deps_m))
168
160
 
@@ -182,8 +174,7 @@ class Task(object):
182
174
  # Mark the source of this data as being this task
183
175
  input.src = self.name
184
176
 
185
- if not os.path.isdir(self.rundir):
186
- os.makedirs(self.rundir)
177
+ self.init_rundir()
187
178
 
188
179
  result = await self.run(input)
189
180
 
@@ -202,9 +193,7 @@ class Task(object):
202
193
  result = self.getOutput()
203
194
 
204
195
  # Write-back the memento, if specified
205
- if self.memento is not None:
206
- with open(os.path.join(self.rundir, "memento.json"), "w") as fp:
207
- fp.write(self.memento.model_dump_json(indent=2))
196
+ self.save_memento()
208
197
 
209
198
  self.running = False
210
199
 
@@ -214,6 +203,15 @@ class Task(object):
214
203
  async def run(self, input : TaskData) -> TaskData:
215
204
  raise NotImplementedError("TaskImpl.run() not implemented")
216
205
 
206
+ def init_rundir(self):
207
+ if not os.path.isdir(self.rundir):
208
+ os.makedirs(self.rundir)
209
+
210
+ def save_memento(self):
211
+ if self.memento is not None:
212
+ with open(os.path.join(self.rundir, "memento.json"), "w") as fp:
213
+ fp.write(self.memento.model_dump_json(indent=2))
214
+
217
215
  def setOutput(self, output : TaskData):
218
216
  self.output_set = True
219
217
  output.src = self.name
dv_flow_mgr/task_data.py CHANGED
@@ -24,6 +24,7 @@ import pydantic.dataclasses as dc
24
24
  from pydantic import BaseModel
25
25
  from typing import Any, Dict, Set, List, Tuple
26
26
  from .fileset import FileSet
27
+ from toposort import toposort
27
28
 
28
29
  class TaskDataParamOpE(enum.Enum):
29
30
  Set = enum.auto()
@@ -32,18 +33,25 @@ class TaskDataParamOpE(enum.Enum):
32
33
  PathAppend = enum.auto()
33
34
  PathPrepend = enum.auto()
34
35
 
36
+ class TaskDataParamKindE(enum.Enum):
37
+ String = enum.auto()
38
+ FilePath = enum.auto()
39
+ SearchPath = enum.auto()
40
+ List = enum.auto()
41
+
35
42
  class TaskDataParamOp(BaseModel):
36
43
  op : TaskDataParamOpE
37
44
  value : Any
38
45
 
39
46
  class TaskDataParam(BaseModel):
40
- value : Any
47
+ kind : TaskDataParamKindE
41
48
  ops : List[TaskDataParamOp] = dc.Field(default_factory=list)
42
49
 
43
50
  class TaskData(BaseModel):
44
51
  src : str = None
45
- params : Dict[str,Any] = dc.Field(default_factory=dict)
52
+ params : Dict[str,TaskDataParam] = dc.Field(default_factory=dict)
46
53
  deps : Dict[str,Set[str]] = dc.Field(default_factory=dict)
54
+ filesets : List[FileSet] = dc.Field(default_factory=list)
47
55
  changed : bool = False
48
56
 
49
57
  def hasParam(self, name: str) -> bool:
@@ -56,16 +64,27 @@ class TaskData(BaseModel):
56
64
  self.params[name] = value
57
65
 
58
66
  def addFileSet(self, fs : FileSet):
59
- fs.src = self.src
60
- if "filesets" not in self.params:
61
- self.params["filesets"] = []
62
- self.params["filesets"].append(fs)
67
+ self.filesets.append(fs)
63
68
 
64
- def getFileSets(self, type=None) -> List[FileSet]:
69
+ def getFileSets(self, type=None, order=True) -> List[FileSet]:
65
70
  ret = []
66
71
 
67
- if "filesets" in self.params:
68
- for fs in self.params["filesets"]:
72
+ if order:
73
+ # The deps map specifies task dependencies
74
+
75
+ candidate_fs = []
76
+ for fs in self.filesets:
77
+ if type is None or fs.type in type:
78
+ candidate_fs.append(fs)
79
+
80
+ order = toposort(self.deps)
81
+
82
+ for order_s in order:
83
+ for fs in candidate_fs:
84
+ if fs.src in order_s:
85
+ ret.append(fs)
86
+ else:
87
+ for fs in self.filesets:
69
88
  if type is None or fs.type in type:
70
89
  ret.append(fs)
71
90
 
@@ -80,15 +99,171 @@ class TaskData(BaseModel):
80
99
  ret.changed = self.changed
81
100
  return ret
82
101
 
83
- def merge(self, other):
84
- for k,v in other.params.items():
85
- if k not in self.params:
86
- if hasattr(v, "copy"):
87
- self.params[k] = v.copy()
102
+ def setParamVal(self, name: str, kind : TaskDataParamKindE, value: Any):
103
+ if name not in self.params:
104
+ self.params[name] = TaskDataParam(kind=kind)
105
+ self.params[name].ops.append(TaskDataParamOp(op=TaskDataParamOpE.Set, value=value))
106
+
107
+ def getParamVal(self, name: str) -> Any:
108
+ if name not in self.params.keys():
109
+ raise Exception("No such parameter: %s" % name)
110
+ param = self.params[name]
111
+ value = param.ops[0].value
112
+
113
+ if len(param.ops) > 1:
114
+ for op in param.ops[1:]:
115
+ if op.op == TaskDataParamOpE.Append:
116
+ if isinstance(value, list):
117
+ value.extend(op.value)
118
+ else:
119
+ value += op.value
120
+ elif op.op == TaskDataParamOpE.Prepend:
121
+ if isinstance(value, list):
122
+ for nv in op.value:
123
+ value.insert(0, nv)
124
+ else:
125
+ value = op.value + value
126
+ elif op.op == TaskDataParamOpE.PathAppend:
127
+ if isinstance(value, list):
128
+ value = ":".join(value)
129
+ value = value + ":" + op.value
130
+ elif op.op == TaskDataParamOpE.PathPrepend:
131
+ if isinstance(value, list):
132
+ value = ":".join(value)
133
+ value = op.value + ":" + value
134
+
135
+ return value
136
+
137
+ @staticmethod
138
+ def merge(incoming : List['TaskData'], local : 'TaskData' = None) -> 'TaskData':
139
+ """Merges incoming data with local settings and produces an output"""
140
+
141
+ # Deal with the dependency trees first
142
+ output = TaskData()
143
+
144
+ # First, merge the dep maps of all the inputs
145
+ output.deps = incoming[0].deps.copy()
146
+ for deps in map(lambda i: i.deps, incoming[1:]):
147
+ for k,v in deps.items():
148
+ if k not in output.deps:
149
+ output.deps[k] = []
150
+ for vi in v:
151
+ if vi not in output.deps[k]:
152
+ output.deps[k].append(v)
153
+
154
+ # Process filesets
155
+ for inp in incoming:
156
+ for fs in inp.filesets:
157
+ exists = False
158
+ for fs_o in output.filesets:
159
+ if fs_o.name == fs.name and fs_o.src == fs.src:
160
+ exists = True
161
+ break
162
+ if not exists:
163
+ output.addFileSet(fs.model_copy())
164
+
165
+ # Now, deal with parameters
166
+ # Find collisions first
167
+ colliding_keys = set()
168
+ passthrough_keys = set()
169
+
170
+ for i in incoming:
171
+ for k in i.params.keys():
172
+ if k in passthrough_keys:
173
+ colliding_keys.add(k)
174
+ else:
175
+ passthrough_keys.add(k)
176
+
177
+ # Now, removes those that are locally set
178
+ local_set_params = set()
179
+ if local is not None:
180
+ for k,v in local.params.items():
181
+ if len(v.ops) == 1 and v.ops[0].op == TaskDataParamOpE.Set:
182
+ local_set_params.add(k)
183
+ # If are setting locally, it's not passthrough
184
+ passthrough_keys.remove(k)
185
+ if k in colliding_keys:
186
+ colliding_keys.remove(k)
187
+
188
+ # Construct the passthrough set by removing
189
+ # colliding entries and those that we will set locally
190
+ for k in colliding_keys:
191
+ if k in passthrough_keys:
192
+ passthrough_keys.remove(k)
193
+
194
+ # For the remaining keys, check for conflicts by
195
+ # confirming that the last 'set' in each incoming parameter
196
+ # are equal
197
+ for k in colliding_keys:
198
+ value = None
199
+ for i,inp in enumerate(incoming):
200
+ value_i = None
201
+ param = inp.params[k]
202
+ if len(param.ops) == 1:
203
+ value_i = param.ops[0].value
204
+ else:
205
+ # Iterate in reverse over the operations
206
+ for op in param.ops[::-1]:
207
+ if op.op == TaskDataParamOpE.Set:
208
+ value_i = op.value
209
+ break
210
+ if not i:
211
+ value = value_i
212
+ else:
213
+ if value != value_i:
214
+ raise Exception("Parameter %s has conflicting values (%s %s)" % (
215
+ k,
216
+ str(value),
217
+ value(value_i)))
218
+
219
+
220
+ # Now, we need to construct the result
221
+ # - copy over passthrough parameters
222
+ # - add locally-set parameters
223
+ # - for others
224
+ # - Apply full list for first input
225
+ # - Apply all beyond the last 'set' operation for others
226
+ for k in passthrough_keys:
227
+ # Find an input that has the parameter
228
+ for inp in incoming:
229
+ if k in inp.params:
230
+ break
231
+ # Find the value of the param
232
+ param = inp.params[k]
233
+
234
+ if len(param.ops) == 1:
235
+ output.params[k] = TaskDataParam(kind=param.kind)
236
+ output.params[k].ops.append(param.ops[0])
237
+ else:
238
+ for op in param.ops[::-1]:
239
+ if op.op == TaskDataParamOpE.Set:
240
+ output.params[k] = TaskDataParam(kind=param.kind)
241
+ output.params[k].ops.append(op)
242
+ break
243
+ for k in local_set_params:
244
+ output.params[k] = local.params[k].model_copy()
245
+
246
+ for k in colliding_keys:
247
+ value = None
248
+ for i,inp in enumerate(incoming):
249
+ # Find the last location that performs a 'set'
250
+ last_set_i = -1
251
+ param = inp.params[k]
252
+ if len(param.ops) == 1:
253
+ last_set_i = 0
254
+ else:
255
+ # Iterate in reverse over the operations
256
+ for j,op in enumerate(param.ops[::-1]):
257
+ if op.op == TaskDataParamOpE.Set:
258
+ last_set_i = j
259
+ break
260
+
261
+ if not i:
262
+ # Copy the full list, including the last 'set'
263
+ output.params[k].ops = param.param[last_set_i:].copy()
88
264
  else:
89
- self.params[k] = v
90
- elif hasattr(self.params[k], "merge"):
91
- self.params[k].merge(v)
92
- elif self.params[k] != v:
93
- raise Exception("Parameter %s has conflicting values" % k)
265
+ # append any additional directives
266
+ if last_set_i+1 < len(param.ops):
267
+ output.params[k].extend(param.ops[last_set_i+1:])
94
268
 
269
+ return output
@@ -0,0 +1,61 @@
1
+ import os
2
+ import sys
3
+ import glob
4
+ import fnmatch
5
+ import importlib
6
+ import pydantic.dataclasses as dc
7
+ from ..package import TaskCtor
8
+ from ..task import Task, TaskParams, TaskCtorT
9
+ from ..task_data import TaskData
10
+ from ..task_memento import TaskMemento
11
+ from typing import List, Tuple
12
+ import dataclasses as dc
13
+ from ..package_def import Package
14
+
15
+ class TaskPyClass(Task):
16
+
17
+ async def run(self, input : TaskData) -> TaskData:
18
+
19
+ if self.srcdir not in sys.path:
20
+ sys.path.insert(0, self.srcdir)
21
+
22
+ print("sys.path: %s" % str(sys.path), flush=True)
23
+ idx = self.params.pyclass.rfind('.')
24
+ modname = self.params.pyclass[:idx]
25
+ clsname = self.params.pyclass[idx+1:]
26
+
27
+ if os.path.isfile(os.path.join(self.basedir, "my_module.py")):
28
+ print("my_module.py exists", flush=True)
29
+ else:
30
+ print("my_module.py does not exist", flush=True)
31
+
32
+ try:
33
+ print("modname=%s" % modname, flush=True)
34
+ module = importlib.import_module(modname)
35
+ except ModuleNotFoundError as e:
36
+ print("Module not found: %s syspath=%s" % (str(e), str(sys.path)), flush=True)
37
+ raise e
38
+
39
+ cls = getattr(module, clsname)
40
+
41
+ obj = cls(self.name, self.task_id, self.session, self.basedir, srcdir=self.srcdir)
42
+
43
+ return await obj.run(input)
44
+
45
+
46
+ class TaskPyClassParams(TaskParams):
47
+ pyclass : str
48
+
49
+ class TaskPyClassMemento(TaskMemento):
50
+ pass
51
+
52
+ class TaskPyClassCtor(TaskCtorT):
53
+ def __init__(self):
54
+ super().__init__(TaskPyClassParams, TaskPyClass)
55
+
56
+ @dc.dataclass
57
+ class PackageBuiltin(Package):
58
+
59
+ def __post_init__(self):
60
+ print("PackageBuiltin::__post_init__", flush=True)
61
+ self.tasks["PyClass"] = TaskPyClass()
@@ -0,0 +1,12 @@
1
+
2
+ package:
3
+ name: std
4
+
5
+ tasks:
6
+ - name: Exec
7
+ uses: builtin.PyClass
8
+ params:
9
+ - name: cmd
10
+ type: string
11
+ - name: pyclass
12
+ type: string
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: dv-flow-mgr
3
- Version: 0.0.1.12761553329a1
3
+ Version: 0.0.1.12822558956a1
4
4
  Summary: DV Flow Manager is a build system for silicon design
5
5
  Author-email: Matthew Ballance <matt.ballance@gmail.com>
6
6
  License: Apache License
@@ -1,6 +1,6 @@
1
1
  dv_flow_mgr/__init__.py,sha256=GLfYxZONxJNNUplfmlsXrcycJ2VhTc8gvXN6qdlH7kg,97
2
2
  dv_flow_mgr/__main__.py,sha256=4xXA4XCqLELlIak6bs-H6rRHp2URucipHPvCiVdR01c,513
3
- dv_flow_mgr/fileset.py,sha256=89knoTNsDF85QJwrctLiM6ryqHS1oxW25Gd5jgpX-IQ,1123
3
+ dv_flow_mgr/fileset.py,sha256=FNvC5sU2ArxJ0OO3v8dXTv8zX-bZ5t0a0ljne0fQQ1o,1150
4
4
  dv_flow_mgr/flow.py,sha256=UdgJOIqBS2wTRpO-sNWCCqO9oQFxDfGPGVD0r42aTrA,1562
5
5
  dv_flow_mgr/fragment_def.py,sha256=p5i6ONtBWlDHTBFsduu3Z36_76Bn8PCIylp_xoZ7jfQ,1552
6
6
  dv_flow_mgr/package.py,sha256=jFhXgKDEYSRfs_VRUjKY4C7KScQfmrNLEXQgtWKaBfI,2767
@@ -8,12 +8,13 @@ dv_flow_mgr/package_def.py,sha256=Js8bZj8bSmJQ6Wk9xAhIBJScNGJOHNbXNhw_zkDVU5w,38
8
8
  dv_flow_mgr/package_import_spec.py,sha256=bStPa727wAKMcixydVY1Ht6ylzXsSMy2K31HWPXhc9k,921
9
9
  dv_flow_mgr/parameters.py,sha256=kUjRss5VtMMz5eL3-Z_M6BS-wFs7MhQu3ANXO54UPo0,896
10
10
  dv_flow_mgr/session.py,sha256=sYRyTojsfPFZOGu4mz9yNTX6ESNye0i5szgj5QVE-Pk,10802
11
- dv_flow_mgr/task.py,sha256=ZTuSulc6lBLcTByD6gQjmbaJqqL1c1mlVtP84iLrLbE,7973
12
- dv_flow_mgr/task_data.py,sha256=32rgwPxSthIjNbzbXK2sZoPo6Jedio_L54Qibu65fYk,2962
11
+ dv_flow_mgr/task.py,sha256=976-6lsx0qarXDgzOHvg8szS1dIjsp1VoQTrcOWUiQE,7723
12
+ dv_flow_mgr/task_data.py,sha256=8AcFCxVmv9agzUDXnwUNJImpfp0N4jB1IHodIECf-0k,9735
13
13
  dv_flow_mgr/task_def.py,sha256=Yjw1Q-bnbi7Ct5X1PriMMNJ6i4TBVFWrO8BTnipz9hg,1532
14
14
  dv_flow_mgr/task_memento.py,sha256=C7VTQpBhDEoYuDmE6YTM-6TLMLnqHp6Y0Vat1aTgtCs,1096
15
15
  dv_flow_mgr/cmds/cmd_run.py,sha256=ii48_jdxCxh4MOJCeKKX66Cui4IvQQy_RrJEIixsph8,733
16
16
  dv_flow_mgr/share/flow.json,sha256=lNmZex9NXkYbyb2aZseQfUOkV9CMyfH0iLODEI7EPBw,5096
17
+ dv_flow_mgr/tasklib/builtin_pkg.py,sha256=qdLUrhF7ZGPpT4EQmtSeOiB4q_tbdLmY6JLxhAYevEA,1746
17
18
  dv_flow_mgr/tasklib/hdl/sim/mti_pkg.py,sha256=l_jerOEQrVSmxT6qJx0PlsorZsK037Y-arQvWzdm9No,348
18
19
  dv_flow_mgr/tasklib/hdl/sim/mti_task_sim_image.py,sha256=U1XADvEGaH412n_JujS1Maz08GJ07UL6mRT4B4qihZQ,2229
19
20
  dv_flow_mgr/tasklib/hdl/sim/mti_task_sim_run.py,sha256=QkKYOs0OhQ42F5bUbfCsezE4L50TfiIm7lVflVY4On8,1290
@@ -27,13 +28,14 @@ dv_flow_mgr/tasklib/hdl/sim/vlt_pkg.py,sha256=Pu9mWAR93kiTNT8GZJrX-VDjMOfr9P5ddc
27
28
  dv_flow_mgr/tasklib/hdl/sim/vlt_task_sim_image.py,sha256=9RDJ3r37C4tA4PIa7tDUYYgRpIh19up-Y9HTOwKxr0I,1564
28
29
  dv_flow_mgr/tasklib/hdl/sim/vlt_task_sim_run.py,sha256=RxPaE1RSRi2QdadrZp2J3lZqTt6EnLjCnk__uPAV6_o,1199
29
30
  dv_flow_mgr/tasklib/std/fileset.py,sha256=u88qjKQpIip_eETk0k6J1AGxk9blKlqAqYinHGKwco8,61
31
+ dv_flow_mgr/tasklib/std/flow.dv,sha256=onqRPp-71uAvLlQdXivvnrIs-OANZC5WYJQMn427TrE,158
30
32
  dv_flow_mgr/tasklib/std/pkg_std.py,sha256=ERDd515qtetQaldk9opUH19MyNwo8nP4-GLz-ke-5gE,370
31
33
  dv_flow_mgr/tasklib/std/std.dfs,sha256=An2NUvvWaR9xI4U-kRQ4NN6U-GhX6GQmd3mNyRkW4NQ,68
32
34
  dv_flow_mgr/tasklib/std/task_fileset.py,sha256=ZBG4e2gsTsRMsr_FhhzIoE3J7YwYQZ9HigpxpGePd74,3145
33
35
  dv_flow_mgr/tasklib/std/task_null.py,sha256=bQH1HN4r-TtdUaJxfnmvoqKZSY4MWO48eK7z_yngdNU,599
34
- dv_flow_mgr-0.0.1.12761553329a1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
35
- dv_flow_mgr-0.0.1.12761553329a1.dist-info/METADATA,sha256=vQplCReVKB6eEKc6Ys_XM6nEB_T1m7Mw35b8ZV_5FzM,13252
36
- dv_flow_mgr-0.0.1.12761553329a1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
37
- dv_flow_mgr-0.0.1.12761553329a1.dist-info/entry_points.txt,sha256=VHxIon5AeHCtK73fYb1veDImAGwv76hrtBiuZePmzhI,51
38
- dv_flow_mgr-0.0.1.12761553329a1.dist-info/top_level.txt,sha256=FGuhGIxN1FgD_YBkPcDq05fTxZcwaX9G_O8FFBvrTk4,12
39
- dv_flow_mgr-0.0.1.12761553329a1.dist-info/RECORD,,
36
+ dv_flow_mgr-0.0.1.12822558956a1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
37
+ dv_flow_mgr-0.0.1.12822558956a1.dist-info/METADATA,sha256=sN9jrnKJpUhpO6NILL6OZBr1jC38YhnbyDtlbt8nESk,13252
38
+ dv_flow_mgr-0.0.1.12822558956a1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
39
+ dv_flow_mgr-0.0.1.12822558956a1.dist-info/entry_points.txt,sha256=VHxIon5AeHCtK73fYb1veDImAGwv76hrtBiuZePmzhI,51
40
+ dv_flow_mgr-0.0.1.12822558956a1.dist-info/top_level.txt,sha256=FGuhGIxN1FgD_YBkPcDq05fTxZcwaX9G_O8FFBvrTk4,12
41
+ dv_flow_mgr-0.0.1.12822558956a1.dist-info/RECORD,,