dv-flow-mgr 0.0.1.12822558956a1__tar.gz → 0.0.1.12911707440a1__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.
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/.github/workflows/ci.yml +1 -1
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/PKG-INFO +1 -1
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/docs/Roadmap.md +14 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/docs/reference.rst +6 -6
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/ivpm.yaml +3 -5
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/pyproject.toml +3 -3
- {dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr → dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr}/__init__.py +1 -1
- {dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr → dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr}/__main__.py +1 -1
- dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr/cmds/cmd_run.py +90 -0
- {dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr → dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr}/package.py +0 -20
- dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr/package_def.py +302 -0
- dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr/pkg_rgy.py +78 -0
- dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr/std/fileset.py +68 -0
- dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr/std/flow.dv +30 -0
- dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr/std/message.py +7 -0
- {dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib → dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr}/std/task_fileset.py +5 -5
- dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr/std/task_null.py +10 -0
- {dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr → dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr}/task.py +33 -72
- {dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr → dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr}/task_data.py +18 -2
- {dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr → dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr}/task_def.py +5 -2
- dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr/task_graph_builder.py +190 -0
- dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr/task_graph_runner.py +71 -0
- dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr/task_graph_runner_local.py +79 -0
- dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr/util.py +19 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/src/dv_flow_mgr.egg-info/PKG-INFO +1 -1
- dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow_mgr.egg-info/SOURCES.txt +69 -0
- dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow_mgr.egg-info/entry_points.txt +2 -0
- dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow_mgr.egg-info/top_level.txt +1 -0
- dv_flow_mgr-0.0.1.12822558956a1/tests/unit/data/fileset/test1/test1.dfs → dv_flow_mgr-0.0.1.12911707440a1/tests/unit/data/fileset/test1/flow.dv +2 -2
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/unit/test_fileset.py +12 -6
- dv_flow_mgr-0.0.1.12911707440a1/tests/unit/test_pyclass.py +181 -0
- dv_flow_mgr-0.0.1.12911707440a1/tests/unit/test_smoke.py +145 -0
- dv_flow_mgr-0.0.1.12911707440a1/tests/unit/test_stdlib.py +27 -0
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/cmds/cmd_run.py +0 -28
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/package_def.py +0 -98
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/session.py +0 -290
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/builtin_pkg.py +0 -61
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/hdl/sim/mti_pkg.py +0 -11
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/hdl/sim/mti_task_sim_image.py +0 -69
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/hdl/sim/mti_task_sim_run.py +0 -47
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/hdl/sim/pkg_hdl_sim.py +0 -8
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/hdl/sim/task_sim_image.py +0 -16
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/hdl/sim/vcs_pkg.py +0 -14
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/hdl/sim/vcs_task_sim_image.py +0 -49
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/hdl/sim/vcs_task_sim_run.py +0 -45
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/hdl/sim/vl_task_sim_image.py +0 -96
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/hdl/sim/vlt_pkg.py +0 -14
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/hdl/sim/vlt_task_sim_image.py +0 -50
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/hdl/sim/vlt_task_sim_run.py +0 -45
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/std/fileset.py +0 -5
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/std/flow.dv +0 -12
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/std/pkg_std.py +0 -15
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/std/std.dfs +0 -7
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr/tasklib/std/task_null.py +0 -26
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr.egg-info/SOURCES.txt +0 -78
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr.egg-info/entry_points.txt +0 -2
- dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr.egg-info/top_level.txt +0 -1
- dv_flow_mgr-0.0.1.12822558956a1/tests/unit/test_pyclass.py +0 -29
- dv_flow_mgr-0.0.1.12822558956a1/tests/unit/test_smoke.py +0 -145
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/.gitignore +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/.vscode/settings.json +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/LICENSE +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/README.md +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/docs/Makefile +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/docs/Notes.md +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/docs/Stages.md +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/docs/TypesAndDefs.md +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/docs/conf.py +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/docs/index.rst +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/docs/intro.rst +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/docs/quickstart.rst +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/setup.cfg +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr → dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr}/fileset.py +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr → dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr}/flow.py +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr → dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr}/fragment_def.py +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr → dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr}/package_import_spec.py +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr → dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr}/parameters.py +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr → dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr}/share/flow.json +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1/src/dv_flow_mgr → dv_flow_mgr-0.0.1.12911707440a1/src/dv_flow/mgr}/task_memento.py +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/src/dv_flow_mgr.egg-info/dependency_links.txt +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/src/dv_flow_mgr.egg-info/requires.txt +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/examples/example1/example1.flow +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/unit/__init__.py +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/unit/data/fileset/test1/files1/file1_1.sv +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/unit/data/fileset/test1/files1/file1_2.sv +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/unit/data/fileset/test1/files2/file2_1.sv +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/unit/data/fileset/test1/files2/file2_2.sv +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/unit/data/fileset/test1 copy/files1/file1_1.sv +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/unit/data/fileset/test1 copy/files1/file1_2.sv +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/unit/data/fileset/test1 copy/files2/file2_1.sv +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/unit/data/fileset/test1 copy/files2/file2_2.sv +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/unit/data/fileset/test1 copy/test1.dfs +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/unit/data/proj1/proj1.dfs +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/unit/data/proj2/proj2.dfs +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/unit/data/proj3/proj3.dfs +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/unit/test_data_merge.py +0 -0
- {dv_flow_mgr-0.0.1.12822558956a1 → dv_flow_mgr-0.0.1.12911707440a1}/tests/unit/test_smoke copy.sav +0 -0
@@ -12,6 +12,18 @@ are evaluated.
|
|
12
12
|
- Operations on input and output data
|
13
13
|
- Operations on task parameters
|
14
14
|
- Package fragments
|
15
|
+
- Define task status. Tasks can have at least two types of failures
|
16
|
+
- Pass/Fail: Fail halts successors
|
17
|
+
- Fail must come with a message and extra info
|
18
|
+
- Status markers/counters
|
19
|
+
- errors / warnings / notes
|
20
|
+
- Want known fileset to capture logfiles and related info
|
21
|
+
- Central params and datasets?
|
22
|
+
- Datasets preserve dependency relationships
|
23
|
+
- Datasets are the best way to aggregate settings
|
24
|
+
- Typed parameter sets
|
25
|
+
- Dependencies provide order in which to evaluate
|
26
|
+
- Operations on variables
|
15
27
|
|
16
28
|
## 2.0.0
|
17
29
|
- Parameterized package definition and use
|
@@ -29,11 +41,13 @@ are evaluated.
|
|
29
41
|
- JQ-based data extraction
|
30
42
|
- YAML task templates / expansions
|
31
43
|
- Support for annotating job requirements
|
44
|
+
- Support capturing schema for structured task data
|
32
45
|
- Mark tasks as producing and accepting certain data
|
33
46
|
- FileSet task `produces` fileset of `type`
|
34
47
|
- SimImage task `accepts` systemVerilogSource, verilogSource, verilogPreCompLib, etc
|
35
48
|
=> Mostly useful for checking and suggestion
|
36
49
|
=> As more are marked, can treat as more binding
|
50
|
+
-
|
37
51
|
|
38
52
|
# Library
|
39
53
|
|
@@ -10,7 +10,7 @@ Each package is defined by the content in its root `flow.yaml` file
|
|
10
10
|
and that in any `fragment` files that are specified in the root
|
11
11
|
package file or its fragments.
|
12
12
|
|
13
|
-
.. jsonschema:: ../src/
|
13
|
+
.. jsonschema:: ../src/dv_flow/mgr/share/flow.json#/defs/package-def
|
14
14
|
|
15
15
|
.. code-block:: yaml
|
16
16
|
|
@@ -24,7 +24,7 @@ package file or its fragments.
|
|
24
24
|
- src/verif
|
25
25
|
|
26
26
|
|
27
|
-
.. jsonschema:: ../src/
|
27
|
+
.. jsonschema:: ../src/dv_flow/mgr/share/flow.json#/defs/fragment-def
|
28
28
|
|
29
29
|
A fragment has similar content to a root-package file.
|
30
30
|
|
@@ -42,12 +42,12 @@ Remember that all fragments referenced by a given package contribute to
|
|
42
42
|
the same package namespace. It would be illegal for another flow file
|
43
43
|
to also define a task named `rtl`.
|
44
44
|
|
45
|
-
.. jsonschema:: ../src/
|
45
|
+
.. jsonschema:: ../src/dv_flow/mgr/share/flow.json#/defs/import-def
|
46
46
|
|
47
|
-
.. jsonschema:: ../src/
|
47
|
+
.. jsonschema:: ../src/dv_flow/mgr/share/flow.json#/defs/param
|
48
48
|
|
49
|
-
.. jsonschema:: ../src/
|
49
|
+
.. jsonschema:: ../src/dv_flow/mgr/share/flow.json#/defs/task-def
|
50
50
|
|
51
|
-
.. jsonschema:: ../src/
|
51
|
+
.. jsonschema:: ../src/dv_flow/mgr/share/flow.json#/defs/task-dep
|
52
52
|
|
53
53
|
And, now, after
|
@@ -1,10 +1,6 @@
|
|
1
1
|
|
2
2
|
package:
|
3
|
-
name:
|
4
|
-
|
5
|
-
# setup-deps:
|
6
|
-
#- ninja
|
7
|
-
#- cython
|
3
|
+
name: dv-flow-mgr
|
8
4
|
|
9
5
|
dep-sets:
|
10
6
|
|
@@ -22,6 +18,8 @@ package:
|
|
22
18
|
- name: svdep
|
23
19
|
url: https://github.com/fvutils/svdep.git
|
24
20
|
anonymous: True
|
21
|
+
- name: dv-flow-lib-hdlsim
|
22
|
+
url: http://github.com/dv-flow/dv-flow-lib-hdlsim.git
|
25
23
|
- name: ply
|
26
24
|
src: pypi
|
27
25
|
- name: pyyaml
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
5
5
|
|
6
6
|
[project]
|
7
7
|
name = "dv-flow-mgr"
|
8
|
-
version = "0.0.1.
|
8
|
+
version = "0.0.1.12911707440a1"
|
9
9
|
dependencies = [
|
10
10
|
"pyyaml",
|
11
11
|
"toposort",
|
@@ -18,8 +18,8 @@ description = "DV Flow Manager is a build system for silicon design"
|
|
18
18
|
license = {file = "LICENSE" }
|
19
19
|
|
20
20
|
[project.scripts]
|
21
|
-
|
21
|
+
dfm = "dv_flow.mgr.__main__:main"
|
22
22
|
|
23
23
|
[tool.setuptools.package-data]
|
24
|
-
|
24
|
+
"dv_flow.mgr" = ['share/*']
|
25
25
|
|
@@ -7,7 +7,7 @@ def get_parser():
|
|
7
7
|
subparsers = parser.add_subparsers(required=True)
|
8
8
|
|
9
9
|
run_parser = subparsers.add_parser('run', help='run a flow')
|
10
|
-
run_parser.add_argument("tasks", nargs='
|
10
|
+
run_parser.add_argument("tasks", nargs='*', help="tasks to run")
|
11
11
|
run_parser.set_defaults(func=CmdRun())
|
12
12
|
|
13
13
|
return parser
|
@@ -0,0 +1,90 @@
|
|
1
|
+
import asyncio
|
2
|
+
import os
|
3
|
+
from ..task_graph_runner import TaskGraphRunner
|
4
|
+
from ..util import loadProjPkgDef
|
5
|
+
from ..task_graph_builder import TaskGraphBuilder
|
6
|
+
from ..task_graph_runner_local import TaskGraphRunnerLocal
|
7
|
+
from ..pkg_rgy import PkgRgy
|
8
|
+
|
9
|
+
|
10
|
+
class CmdRun(object):
|
11
|
+
|
12
|
+
def __call__(self, args):
|
13
|
+
|
14
|
+
# First, find the project we're working with
|
15
|
+
pkg = loadProjPkgDef(os.getcwd())
|
16
|
+
|
17
|
+
if pkg is None:
|
18
|
+
raise Exception("Failed to find a 'flow.dv' file that defines a package in %s or its parent directories" % os.getcwd())
|
19
|
+
|
20
|
+
print("pkg: %s" % pkg.name)
|
21
|
+
|
22
|
+
if len(args.tasks) > 0:
|
23
|
+
pass
|
24
|
+
else:
|
25
|
+
# Print out available tasks
|
26
|
+
tasks = []
|
27
|
+
for task in pkg.tasks:
|
28
|
+
tasks.append(task)
|
29
|
+
for frag in pkg.fragment_l:
|
30
|
+
for task in frag.tasks:
|
31
|
+
tasks.append(task)
|
32
|
+
tasks.sort(key=lambda x: x.name)
|
33
|
+
|
34
|
+
max_name_len = 0
|
35
|
+
for t in tasks:
|
36
|
+
if len(t.name) > max_name_len:
|
37
|
+
max_name_len = len(t.name)
|
38
|
+
|
39
|
+
print("No task specified. Available Tasks:")
|
40
|
+
for t in tasks:
|
41
|
+
desc = t.desc
|
42
|
+
if desc is None or t.desc == "":
|
43
|
+
"<no descripion>"
|
44
|
+
print("%s - %s" % (t.name.ljust(max_name_len), desc))
|
45
|
+
|
46
|
+
pass
|
47
|
+
|
48
|
+
# Create a session around <pkg>
|
49
|
+
# Need to select a backend
|
50
|
+
# Need somewhere to store project config data
|
51
|
+
# Maybe separate into a task-graph builder and a task-graph runner
|
52
|
+
|
53
|
+
# TODO: allow user to specify run root -- maybe relative to some fixed directory?
|
54
|
+
rundir = os.path.join(pkg.basedir, "rundir")
|
55
|
+
|
56
|
+
builder = TaskGraphBuilder(root_pkg=pkg, rundir=rundir)
|
57
|
+
runner = TaskGraphRunnerLocal(rundir)
|
58
|
+
|
59
|
+
tasks = []
|
60
|
+
|
61
|
+
for spec in args.tasks:
|
62
|
+
task = builder.mkTaskGraph(spec)
|
63
|
+
tasks.append(task)
|
64
|
+
|
65
|
+
asyncio.run(runner.run(tasks))
|
66
|
+
|
67
|
+
# rgy = PkgRgy.inst()
|
68
|
+
# rgy.registerPackage(pkg)
|
69
|
+
|
70
|
+
|
71
|
+
# srcdir = os.getcwd()
|
72
|
+
|
73
|
+
# session = Session(srcdir, rundir)
|
74
|
+
|
75
|
+
# package = session.load(srcdir)
|
76
|
+
|
77
|
+
# graphs = []
|
78
|
+
# for task in args.tasks:
|
79
|
+
# if task.find(".") == -1:
|
80
|
+
# task = package.name + "." + task
|
81
|
+
# subgraph = session.mkTaskGraph(task)
|
82
|
+
# graphs.append(subgraph)
|
83
|
+
|
84
|
+
# awaitables = [subgraph.do_run() for subgraph in graphs]
|
85
|
+
# print("%d awaitables" % len(awaitables))
|
86
|
+
|
87
|
+
# out = asyncio.get_event_loop().run_until_complete(asyncio.gather(*awaitables))
|
88
|
+
|
89
|
+
# print("out: %s" % str(out))
|
90
|
+
|
@@ -54,26 +54,6 @@ class Package(object):
|
|
54
54
|
def getTaskCtor(self, name : str) -> TaskCtor:
|
55
55
|
return self.tasks[name]
|
56
56
|
|
57
|
-
def mkTaskParams(self, name : str) -> TaskParams:
|
58
|
-
if name not in self.tasks:
|
59
|
-
raise Exception("Task " + name + " not found")
|
60
|
-
return self.tasks[name].mkTaskParams()
|
61
|
-
|
62
|
-
def setTaskParams(self, name : str, params : TaskParams, pvals : Dict[str,Any]):
|
63
|
-
if name not in self.tasks:
|
64
|
-
raise Exception("Task " + name + " not found")
|
65
|
-
self.tasks[name].setTaskParams(params, pvals)
|
66
|
-
|
67
|
-
def mkTask(self,
|
68
|
-
name : str,
|
69
|
-
task_id : int,
|
70
|
-
session : 'Session',
|
71
|
-
params : TaskParams,
|
72
|
-
depends : List['Task']) -> 'Task':
|
73
|
-
# TODO: combine parameters to create the full taskname
|
74
|
-
task = self.tasks[name].mkTask(name, task_id, session, params, depends)
|
75
|
-
return task
|
76
|
-
|
77
57
|
def __hash__(self):
|
78
58
|
return hash(self.fullname())
|
79
59
|
|
@@ -0,0 +1,302 @@
|
|
1
|
+
#****************************************************************************
|
2
|
+
#* package_def.py
|
3
|
+
#*
|
4
|
+
#* Copyright 2023 Matthew Ballance and Contributors
|
5
|
+
#*
|
6
|
+
#* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
7
|
+
#* not use this file except in compliance with the License.
|
8
|
+
#* You may obtain a copy of the License at:
|
9
|
+
#*
|
10
|
+
#* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#*
|
12
|
+
#* Unless required by applicable law or agreed to in writing, software
|
13
|
+
#* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
#* See the License for the specific language governing permissions and
|
16
|
+
#* limitations under the License.
|
17
|
+
#*
|
18
|
+
#* Created on:
|
19
|
+
#* Author:
|
20
|
+
#*
|
21
|
+
#****************************************************************************
|
22
|
+
import os
|
23
|
+
import json
|
24
|
+
import yaml
|
25
|
+
import importlib
|
26
|
+
import sys
|
27
|
+
import pydantic
|
28
|
+
import pydantic.dataclasses as dc
|
29
|
+
from pydantic import BaseModel
|
30
|
+
from typing import Any, Dict, List, Callable, Tuple
|
31
|
+
from .flow import Flow
|
32
|
+
from .fragment_def import FragmentDef
|
33
|
+
from .package import Package
|
34
|
+
from .package_import_spec import PackageImportSpec, PackageSpec
|
35
|
+
from .task import TaskCtor, TaskParams
|
36
|
+
from .task_def import TaskDef, TaskSpec
|
37
|
+
from .std.task_null import TaskNull
|
38
|
+
|
39
|
+
|
40
|
+
class PackageDef(BaseModel):
|
41
|
+
name : str
|
42
|
+
params : Dict[str,Any] = dc.Field(default_factory=dict)
|
43
|
+
type : List[PackageSpec] = dc.Field(default_factory=list)
|
44
|
+
tasks : List[TaskDef] = dc.Field(default_factory=list)
|
45
|
+
imports : List[PackageImportSpec] = dc.Field(default_factory=list)
|
46
|
+
fragments: List[str] = dc.Field(default_factory=list)
|
47
|
+
|
48
|
+
fragment_l : List['FragmentDef'] = dc.Field(default_factory=list, exclude=True)
|
49
|
+
|
50
|
+
# import_m : Dict['PackageSpec','Package'] = dc.Field(default_factory=dict)
|
51
|
+
|
52
|
+
basedir : str = None
|
53
|
+
|
54
|
+
def getTask(self, name : str) -> 'TaskDef':
|
55
|
+
for t in self.tasks:
|
56
|
+
if t.name == name:
|
57
|
+
return t
|
58
|
+
|
59
|
+
def mkPackage(self, session, params : Dict[str,Any] = None) -> 'Package':
|
60
|
+
ret = Package(self.name)
|
61
|
+
|
62
|
+
session.push_package(ret)
|
63
|
+
|
64
|
+
tasks_m : Dict[str,str,TaskCtor]= {}
|
65
|
+
|
66
|
+
for task in self.tasks:
|
67
|
+
if task.name in tasks_m.keys():
|
68
|
+
raise Exception("Duplicate task %s" % task.name)
|
69
|
+
tasks_m[task.name] = (task, self.basedir, ) # We'll add a TaskCtor later
|
70
|
+
|
71
|
+
for frag in self.fragment_l:
|
72
|
+
for task in frag.tasks:
|
73
|
+
if task.name in tasks_m.keys():
|
74
|
+
raise Exception("Duplicate task %s" % task.name)
|
75
|
+
tasks_m[task.name] = (task, frag.basedir, ) # We'll add a TaskCtor later
|
76
|
+
|
77
|
+
# Now we have a unified map of the tasks declared in this package
|
78
|
+
for name in list(tasks_m.keys()):
|
79
|
+
task_i = tasks_m[name]
|
80
|
+
if len(task_i) < 3:
|
81
|
+
# Need to create the task ctor
|
82
|
+
ctor_t = self.mkTaskCtor(session, task_i[0], task_i[1], tasks_m)
|
83
|
+
tasks_m[name] = (task_i[0], task_i[1], ctor_t)
|
84
|
+
ret.tasks[name] = tasks_m[name][2]
|
85
|
+
|
86
|
+
session.pop_package(ret)
|
87
|
+
|
88
|
+
return ret
|
89
|
+
|
90
|
+
def mkTaskCtor(self, session, task, srcdir, tasks_m) -> TaskCtor:
|
91
|
+
ctor_t : TaskCtor = None
|
92
|
+
|
93
|
+
if task.uses is not None:
|
94
|
+
# Find package (not package_def) that implements this task
|
95
|
+
# Insert an indirect reference to that tasks's constructor
|
96
|
+
last_dot = task.uses.rfind('.')
|
97
|
+
|
98
|
+
if last_dot != -1:
|
99
|
+
pkg_name = task.uses[:last_dot]
|
100
|
+
task_name = task.uses[last_dot+1:]
|
101
|
+
else:
|
102
|
+
pkg_name = None
|
103
|
+
task_name = task.uses
|
104
|
+
|
105
|
+
if pkg_name is not None:
|
106
|
+
pkg = session.getPackage(PackageSpec(pkg_name))
|
107
|
+
if pkg is None:
|
108
|
+
raise Exception("Failed to find package %s" % pkg_name)
|
109
|
+
ctor_t = pkg.getTaskCtor(task_name)
|
110
|
+
ctor_t = ctor_t.copy()
|
111
|
+
ctor_t.srcdir = srcdir
|
112
|
+
else:
|
113
|
+
if task_name not in tasks_m.keys():
|
114
|
+
raise Exception("Failed to find task %s" % task_name)
|
115
|
+
if len(tasks_m[task_name]) == 3:
|
116
|
+
ctor_t = tasks_m[task_name][2].copy()
|
117
|
+
ctor_t.srcdir = srcdir
|
118
|
+
else:
|
119
|
+
task_i = tasks_m[task_name]
|
120
|
+
ctor_t = self.mkTaskCtor(
|
121
|
+
session,
|
122
|
+
task=task_i[0],
|
123
|
+
srcdir=srcdir,
|
124
|
+
tasks_m=tasks_m)
|
125
|
+
tasks_m[task_name] = ctor_t
|
126
|
+
|
127
|
+
if ctor_t is None:
|
128
|
+
# Provide a default implementation
|
129
|
+
ctor_t = TaskCtor(
|
130
|
+
task_ctor=TaskNull,
|
131
|
+
param_ctor=TaskParams,
|
132
|
+
srcdir=srcdir)
|
133
|
+
|
134
|
+
if task.pyclass is not None:
|
135
|
+
# Built-in impl
|
136
|
+
# Now, lookup the class
|
137
|
+
last_dot = task.pyclass.rfind('.')
|
138
|
+
clsname = task.pyclass[last_dot+1:]
|
139
|
+
modname = task.pyclass[:last_dot]
|
140
|
+
|
141
|
+
try:
|
142
|
+
if modname not in sys.modules:
|
143
|
+
if self.basedir not in sys.path:
|
144
|
+
sys.path.append(self.basedir)
|
145
|
+
mod = importlib.import_module(modname)
|
146
|
+
else:
|
147
|
+
mod = sys.modules[modname]
|
148
|
+
except ModuleNotFoundError as e:
|
149
|
+
raise Exception("Failed to import module %s (basedir=%s): %s" % (
|
150
|
+
modname, self.basedir, str(e)))
|
151
|
+
|
152
|
+
if not hasattr(mod, clsname):
|
153
|
+
raise Exception("Class %s not found in module %s" % (clsname, modname))
|
154
|
+
ctor_t.task_ctor = getattr(mod, clsname)
|
155
|
+
|
156
|
+
if task.uses is None:
|
157
|
+
ctor_t.param_ctor = TaskParams
|
158
|
+
|
159
|
+
decl_params = False
|
160
|
+
for value in task.params.values():
|
161
|
+
if "type" in value:
|
162
|
+
decl_params = True
|
163
|
+
break
|
164
|
+
|
165
|
+
if decl_params:
|
166
|
+
# We need to combine base parameters with new parameters
|
167
|
+
field_m = {}
|
168
|
+
# First, add parameters from the base class
|
169
|
+
for fname,info in ctor_t.param_ctor.model_fields.items():
|
170
|
+
print("Field: %s (%s)" % (fname, info.default))
|
171
|
+
field_m[fname] = (info.annotation, info.default)
|
172
|
+
ptype_m = {
|
173
|
+
"str" : str,
|
174
|
+
"int" : int,
|
175
|
+
"float" : float,
|
176
|
+
"bool" : bool,
|
177
|
+
"list" : List
|
178
|
+
}
|
179
|
+
pdflt_m = {
|
180
|
+
"str" : "",
|
181
|
+
"int" : 0,
|
182
|
+
"float" : 0.0,
|
183
|
+
"bool" : False,
|
184
|
+
"list" : []
|
185
|
+
}
|
186
|
+
for p in task.params.keys():
|
187
|
+
param = task.params[p]
|
188
|
+
if type(param) == dict and "type" in param.keys():
|
189
|
+
ptype_s = param["type"]
|
190
|
+
if ptype_s not in ptype_m.keys():
|
191
|
+
raise Exception("Unknown type %s" % ptype_s)
|
192
|
+
ptype = ptype_m[ptype_s]
|
193
|
+
|
194
|
+
if p in field_m.keys():
|
195
|
+
raise Exception("Duplicate field %s" % p)
|
196
|
+
if "value" in param.keys():
|
197
|
+
field_m[p] = (ptype, param["value"])
|
198
|
+
else:
|
199
|
+
field_m[p] = (ptype, pdflt_m[ptype_s])
|
200
|
+
else:
|
201
|
+
if p not in field_m.keys():
|
202
|
+
raise Exception("Field %s not found" % p)
|
203
|
+
if type(param) != dict:
|
204
|
+
value = param
|
205
|
+
elif "value" in param.keys():
|
206
|
+
value = param["value"]
|
207
|
+
else:
|
208
|
+
raise Exception("No value specified for param %s: %s" % (
|
209
|
+
p, str(param)))
|
210
|
+
field_m[p] = (field_m[p][0], value)
|
211
|
+
print("field_m: %s" % str(field_m))
|
212
|
+
ctor_t.param_ctor = pydantic.create_model(
|
213
|
+
"Task%sParams" % task.name, **field_m)
|
214
|
+
else:
|
215
|
+
if len(task.params) > 0:
|
216
|
+
ctor_t.params = task.params
|
217
|
+
if len(task.depends) > 0:
|
218
|
+
ctor_t.depends.extends(task.depends)
|
219
|
+
|
220
|
+
return ctor_t
|
221
|
+
|
222
|
+
@staticmethod
|
223
|
+
def load(path, exp_pkg_name=None):
|
224
|
+
return PackageDef._loadPkgDef(path, exp_pkg_name, [])
|
225
|
+
pass
|
226
|
+
|
227
|
+
@staticmethod
|
228
|
+
def _loadPkgDef(root, exp_pkg_name, file_s):
|
229
|
+
if root in file_s:
|
230
|
+
raise Exception("Recursive file processing @ %s: %s" % (root, ",".join(file_s)))
|
231
|
+
file_s.append(root)
|
232
|
+
ret = None
|
233
|
+
with open(root, "r") as fp:
|
234
|
+
print("open %s" % root)
|
235
|
+
doc = yaml.load(fp, Loader=yaml.FullLoader)
|
236
|
+
if "package" not in doc.keys():
|
237
|
+
raise Exception("Missing 'package' key in %s" % root)
|
238
|
+
pkg = PackageDef(**(doc["package"]))
|
239
|
+
pkg.basedir = os.path.dirname(root)
|
240
|
+
|
241
|
+
# for t in pkg.tasks:
|
242
|
+
# t.basedir = os.path.dirname(root)
|
243
|
+
|
244
|
+
if exp_pkg_name is not None:
|
245
|
+
if exp_pkg_name != pkg.name:
|
246
|
+
raise Exception("Package name mismatch: %s != %s" % (exp_pkg_name, pkg.name))
|
247
|
+
# else:
|
248
|
+
# self._pkg_m[exp_pkg_name] = [PackageSpec(pkg.name)
|
249
|
+
# self._pkg_spec_s.append(PackageSpec(pkg.name))
|
250
|
+
|
251
|
+
# if not len(self._pkg_spec_s):
|
252
|
+
# self._pkg_spec_s.append(PackageSpec(pkg.name))
|
253
|
+
# else:
|
254
|
+
# self._pkg_def_m[PackageSpec(pkg.name)] = pkg
|
255
|
+
|
256
|
+
print("pkg: %s" % str(pkg))
|
257
|
+
|
258
|
+
print("fragments: %s" % str(pkg.fragments))
|
259
|
+
for spec in pkg.fragments:
|
260
|
+
PackageDef._loadFragmentSpec(pkg, spec, file_s)
|
261
|
+
|
262
|
+
file_s.pop()
|
263
|
+
|
264
|
+
return pkg
|
265
|
+
|
266
|
+
@staticmethod
|
267
|
+
def _loadFragmentSpec(pkg, spec, file_s):
|
268
|
+
# We're either going to have:
|
269
|
+
# - File path
|
270
|
+
# - Directory path
|
271
|
+
|
272
|
+
if os.path.isfile(os.path.join(pkg.basedir, spec)):
|
273
|
+
PackageDef._loadFragmentFile(pkg, spec, file_s)
|
274
|
+
elif os.path.isdir(os.path.join(pkg.basedir, spec)):
|
275
|
+
PackageDef._loadFragmentDir(pkg, os.path.join(pkg.basedir, spec), file_s)
|
276
|
+
else:
|
277
|
+
raise Exception("Fragment spec %s not found" % spec)
|
278
|
+
|
279
|
+
@staticmethod
|
280
|
+
def _loadFragmentDir(pkg, dir, file_s):
|
281
|
+
for file in os.listdir(dir):
|
282
|
+
if os.path.isdir(os.path.join(dir, file)):
|
283
|
+
PackageDef._loadFragmentDir(pkg, os.path.join(dir, file), file_s)
|
284
|
+
elif os.path.isfile(os.path.join(dir, file)) and file == "flow.dv":
|
285
|
+
PackageDef._loadFragmentFile(pkg, os.path.join(dir, file), file_s)
|
286
|
+
|
287
|
+
@staticmethod
|
288
|
+
def _loadFragmentFile(pkg, file, file_s):
|
289
|
+
if file in file_s:
|
290
|
+
raise Exception("Recursive file processing @ %s: %s" % (file, ", ".join(file_s)))
|
291
|
+
file_s.append(file)
|
292
|
+
|
293
|
+
with open(file, "r") as fp:
|
294
|
+
doc = yaml.load(fp, Loader=yaml.FullLoader)
|
295
|
+
print("doc: %s" % str(doc), flush=True)
|
296
|
+
if "fragment" in doc.keys():
|
297
|
+
# Merge the package definition
|
298
|
+
frag = FragmentDef(**(doc["fragment"]))
|
299
|
+
frag.basedir = os.path.dirname(file)
|
300
|
+
pkg.fragment_l.append(frag)
|
301
|
+
else:
|
302
|
+
print("Warning: file %s is not a fragment" % file)
|
@@ -0,0 +1,78 @@
|
|
1
|
+
import os
|
2
|
+
import sys
|
3
|
+
from typing import Dict, Tuple
|
4
|
+
from .package_def import PackageDef
|
5
|
+
|
6
|
+
class PkgRgy(object):
|
7
|
+
_inst = None
|
8
|
+
|
9
|
+
def __init__(self):
|
10
|
+
self._pkgpath = []
|
11
|
+
self._pkg_m : Dict[str, Tuple[str,PackageDef]] = {}
|
12
|
+
|
13
|
+
def hasPackage(self, name, search_path=False):
|
14
|
+
if name in self._pkg_m.keys():
|
15
|
+
return True
|
16
|
+
elif search_path:
|
17
|
+
for p in self._pkgpath:
|
18
|
+
if os.path.exists(os.path.join(p, name)):
|
19
|
+
return True
|
20
|
+
else:
|
21
|
+
return False
|
22
|
+
|
23
|
+
def getPackage(self, name):
|
24
|
+
if name in self._pkg_m.keys():
|
25
|
+
if self._pkg_m[name][1] is None:
|
26
|
+
pkg_def = PackageDef.load(self._pkg_m[name][0])
|
27
|
+
# Load the package
|
28
|
+
self._pkg_m[name] = (
|
29
|
+
self._pkg_m[name][0],
|
30
|
+
pkg_def
|
31
|
+
)
|
32
|
+
pass
|
33
|
+
return self._pkg_m[name][1]
|
34
|
+
else:
|
35
|
+
# Go search the package path
|
36
|
+
return None
|
37
|
+
|
38
|
+
def registerPackage(self, pkg_def):
|
39
|
+
if pkg_def.name in self._pkg_m.keys():
|
40
|
+
raise Exception("Duplicate package %s" % pkg_def.name)
|
41
|
+
self._pkg_m[pkg_def.name] = pkg_def
|
42
|
+
|
43
|
+
def _discover_plugins(self):
|
44
|
+
# Register built-in package
|
45
|
+
self._pkg_m["std"] = (os.path.join(os.path.dirname(__file__), "std/flow.dv"), None)
|
46
|
+
|
47
|
+
if sys.version_info < (3,10):
|
48
|
+
from importlib_metadata import entry_points
|
49
|
+
else:
|
50
|
+
from importlib.metadata import entry_points
|
51
|
+
|
52
|
+
discovered_plugins = entry_points(group='dv_flow.mgr')
|
53
|
+
for p in discovered_plugins:
|
54
|
+
try:
|
55
|
+
mod = p.load()
|
56
|
+
|
57
|
+
if hasattr(mod, "dvfm_packages"):
|
58
|
+
pkg_m = mod.dvfm_packages()
|
59
|
+
|
60
|
+
for name,path in pkg_m.items():
|
61
|
+
if name in self._pkg_m.keys():
|
62
|
+
raise Exception("Package %s already registered using path %s. Conflicting path: %s" % (
|
63
|
+
name, self._pkg_m[name][0], path))
|
64
|
+
self._pkg_m[name] = (path, None)
|
65
|
+
except Exception as e:
|
66
|
+
print("Error loading plugin %s: %s" % (p.name, str(e)))
|
67
|
+
raise e
|
68
|
+
|
69
|
+
# self._pkgs = {}
|
70
|
+
# for pkg in self._load_pkg_list():
|
71
|
+
# self._pkgs[pkg.name] = pkg
|
72
|
+
|
73
|
+
@classmethod
|
74
|
+
def inst(cls):
|
75
|
+
if cls._inst is None:
|
76
|
+
cls._inst = cls()
|
77
|
+
cls._inst._discover_plugins()
|
78
|
+
return cls._inst
|