opencos-eda 0.3.9__tar.gz → 0.3.10__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.
- {opencos_eda-0.3.9/opencos_eda.egg-info → opencos_eda-0.3.10}/PKG-INFO +1 -1
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/deps_help.py +40 -21
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/sim.py +0 -1
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/deps/deps_file.py +82 -79
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/eda.py +46 -9
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/eda_base.py +8 -4
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/eda_config.py +8 -1
- opencos_eda-0.3.10/opencos/eda_deps_bash_completion.bash +77 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/questa_common.py +1 -2
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/verilator.py +1 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/utils/str_helpers.py +7 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/utils/vsim_helper.py +47 -22
- {opencos_eda-0.3.9 → opencos_eda-0.3.10/opencos_eda.egg-info}/PKG-INFO +1 -1
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos_eda.egg-info/SOURCES.txt +0 -18
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos_eda.egg-info/entry_points.txt +1 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/pyproject.toml +19 -11
- opencos_eda-0.3.9/opencos/eda_deps_bash_completion.bash +0 -55
- opencos_eda-0.3.9/opencos/tests/custom_config.yml +0 -13
- opencos_eda-0.3.9/opencos/tests/deps_files/command_order/DEPS.yml +0 -44
- opencos_eda-0.3.9/opencos/tests/deps_files/error_msgs/DEPS.yml +0 -55
- opencos_eda-0.3.9/opencos/tests/deps_files/iverilog_test/DEPS.yml +0 -4
- opencos_eda-0.3.9/opencos/tests/deps_files/no_deps_here/DEPS.yml +0 -0
- opencos_eda-0.3.9/opencos/tests/deps_files/non_sv_reqs/DEPS.yml +0 -50
- opencos_eda-0.3.9/opencos/tests/deps_files/tags_with_tools/DEPS.yml +0 -54
- opencos_eda-0.3.9/opencos/tests/deps_files/test_err_fatal/DEPS.yml +0 -4
- opencos_eda-0.3.9/opencos/tests/helpers.py +0 -354
- opencos_eda-0.3.9/opencos/tests/test_build.py +0 -12
- opencos_eda-0.3.9/opencos/tests/test_deps_helpers.py +0 -207
- opencos_eda-0.3.9/opencos/tests/test_deps_schema.py +0 -30
- opencos_eda-0.3.9/opencos/tests/test_eda.py +0 -921
- opencos_eda-0.3.9/opencos/tests/test_eda_elab.py +0 -110
- opencos_eda-0.3.9/opencos/tests/test_eda_synth.py +0 -150
- opencos_eda-0.3.9/opencos/tests/test_oc_cli.py +0 -25
- opencos_eda-0.3.9/opencos/tests/test_tools.py +0 -404
- opencos_eda-0.3.9/opencos/utils/__init__.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/LICENSE +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/LICENSE.spdx +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/README.md +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/__init__.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/_version.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/_waves_pkg.sv +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/__init__.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/build.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/elab.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/export.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/flist.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/lec.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/lint.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/multi.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/open.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/proj.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/shell.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/sweep.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/synth.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/targets.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/upload.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/commands/waves.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/deps/__init__.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/deps/defaults.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/deps/deps_commands.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/deps/deps_processor.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/deps_schema.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/eda_config_defaults.yml +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/eda_config_max_verilator_waivers.yml +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/eda_config_reduced.yml +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/eda_deps_sanitize.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/eda_extract_targets.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/eda_tool_helper.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/export_helper.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/export_json_convert.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/files.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/hw/__init__.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/hw/oc_cli.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/hw/pcie.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/names.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/peakrdl_cleanup.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/seed.py +0 -0
- {opencos_eda-0.3.9/opencos/tests → opencos_eda-0.3.10/opencos/tools}/__init__.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/cocotb.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/invio.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/invio_helpers.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/invio_yosys.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/iverilog.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/modelsim_ase.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/quartus.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/questa.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/questa_fe.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/questa_fse.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/riviera.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/slang.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/slang_yosys.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/surelog.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/tabbycad_yosys.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/vivado.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/tools/yosys.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/util.py +0 -0
- {opencos_eda-0.3.9/opencos/tools → opencos_eda-0.3.10/opencos/utils}/__init__.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/utils/markup_helpers.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/utils/status_constants.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/utils/subprocess_helpers.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos/utils/vscode_helper.py +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos_eda.egg-info/dependency_links.txt +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos_eda.egg-info/requires.txt +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/opencos_eda.egg-info/top_level.txt +0 -0
- {opencos_eda-0.3.9 → opencos_eda-0.3.10}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencos-eda
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.10
|
|
4
4
|
Summary: A simple Python package for wrapping RTL simuliatons and synthesis
|
|
5
5
|
Author-email: Simon Sabato <simon@cognichip.ai>, Drew Ranck <drew@cognichip.ai>
|
|
6
6
|
Project-URL: Homepage, https://github.com/cognichip/opencos
|
|
@@ -10,32 +10,37 @@ it is generally run as simply
|
|
|
10
10
|
uses no tools and will print a help text regarding DEPS markup files to stdout.
|
|
11
11
|
'''
|
|
12
12
|
|
|
13
|
+
# pylint: disable=line-too-long
|
|
13
14
|
|
|
14
15
|
import os
|
|
15
16
|
|
|
16
17
|
from opencos.eda_base import Command
|
|
17
18
|
from opencos import util
|
|
19
|
+
from opencos.util import Colors
|
|
18
20
|
|
|
19
21
|
|
|
20
|
-
BASIC_DEPS_HELP = '''
|
|
22
|
+
BASIC_DEPS_HELP = f'''
|
|
23
|
+
{Colors.yellow}
|
|
24
|
+
Note: you can run with one of: {Colors.cyan}--verbose, --help, --debug{Colors.yellow} to show full
|
|
25
|
+
schema supported, or {Colors.cyan}--no-color{Colors.yellow} to avoid printing this text with colors.
|
|
21
26
|
|
|
22
|
-
--------------------------------------------------------------------
|
|
27
|
+
{Colors.green}--------------------------------------------------------------------{Colors.yellow}
|
|
23
28
|
|
|
24
|
-
What is a DEPS.yml file and why does `eda` use this?
|
|
25
|
-
- DEPS.yml is a fancy filelist.
|
|
29
|
+
What is a {Colors.byellow}DEPS.yml{Colors.normal}{Colors.yellow} file and why does `eda` use this?
|
|
30
|
+
- {Colors.byellow}DEPS.yml{Colors.normal}{Colors.yellow} is a fancy filelist.
|
|
26
31
|
- Used to organize a project into "targets", a tool can run on a "target".
|
|
27
32
|
- Allows for more than just source files attached to a "target".
|
|
28
33
|
-- incdirs, defines, and args can be applied to a "target".
|
|
29
34
|
|
|
30
|
-
--------------------------------------------------------------------
|
|
35
|
+
{Colors.green}--------------------------------------------------------------------{Colors.yellow}
|
|
31
36
|
|
|
32
37
|
Hello World example:
|
|
33
38
|
|
|
34
|
-
The following example is a DEPS.yml file example for a SystemVerilog simulation of
|
|
35
|
-
hello_world_tb.sv. DEPS.yml is, in short, a fancy filelist. We use them in the `eda`
|
|
39
|
+
The following example is a {Colors.byellow}DEPS.yml{Colors.normal}{Colors.yellow} file example for a SystemVerilog simulation of
|
|
40
|
+
hello_world_tb.sv. {Colors.byellow}DEPS.yml{Colors.normal}{Colors.yellow} is, in short, a fancy filelist. We use them in the `eda`
|
|
36
41
|
app to organize projects.
|
|
37
42
|
|
|
38
|
-
--- DEPS.yml: ---
|
|
43
|
+
--- {Colors.byellow}DEPS.yml{Colors.normal}{Colors.yellow}: ---
|
|
39
44
|
|
|
40
45
|
hello-world: # <-- this is a named target that will be run
|
|
41
46
|
|
|
@@ -64,20 +69,20 @@ endmodule : hello_world_tb
|
|
|
64
69
|
|
|
65
70
|
|
|
66
71
|
hello-world:
|
|
67
|
-
The target name in the DEPS.yml we named is hello-world. That is a valid target
|
|
72
|
+
The target name in the {Colors.byellow}DEPS.yml{Colors.normal}{Colors.yellow} we named is hello-world. That is a valid target
|
|
68
73
|
that `eda` can use. Such as:
|
|
69
74
|
|
|
70
75
|
eda sim --tool=verilator hello-world
|
|
71
76
|
|
|
72
77
|
|
|
73
|
-
--------------------------------------------------------------------
|
|
78
|
+
{Colors.green}--------------------------------------------------------------------{Colors.yellow}
|
|
74
79
|
|
|
75
80
|
Beyond Hello World example:
|
|
76
81
|
|
|
77
82
|
The following example is a DEPS.yml file for a more complex module simulation.
|
|
78
83
|
It has two files in ./DEPS.yml and ./lib/DEPS.yml.
|
|
79
84
|
|
|
80
|
-
--- ./DEPS.yml: ---
|
|
85
|
+
--- {Colors.byellow}./DEPS.yml{Colors.normal}{Colors.yellow}: ---
|
|
81
86
|
|
|
82
87
|
my_fifo: # <-- this is a design
|
|
83
88
|
incdirs: . lib # <-- 'incdirs' define the paths searched to find `include files
|
|
@@ -102,7 +107,7 @@ my_fifo_stress_test: # <-- this is another TEST
|
|
|
102
107
|
deps:
|
|
103
108
|
- my_fifo_test # aside from the define, this is same as "my_fifo_test"
|
|
104
109
|
|
|
105
|
-
--- lib/DEPS.yml: ---
|
|
110
|
+
--- {Colors.byellow}lib/DEPS.yml{Colors.normal}{Colors.yellow}: ---
|
|
106
111
|
|
|
107
112
|
lib_pkg: # <-- this is a package required by bin_to_gray below
|
|
108
113
|
deps:
|
|
@@ -115,15 +120,15 @@ bin_to_gray: # <-- this is the target that was required by .
|
|
|
115
120
|
# to be read before the code that uses them
|
|
116
121
|
- bin_to_gray.sv # an SV module pulled in directly
|
|
117
122
|
|
|
118
|
-
--------------------------------------------------------------------
|
|
123
|
+
{Colors.green}--------------------------------------------------------------------{Colors.yellow}
|
|
119
124
|
'''
|
|
120
125
|
|
|
121
126
|
|
|
122
|
-
FULL_DEPS_HELP = '''
|
|
127
|
+
FULL_DEPS_HELP = f'''
|
|
123
128
|
|
|
124
|
-
--------------------------------------------------------------------
|
|
129
|
+
{Colors.green}--------------------------------------------------------------------{Colors.yellow}
|
|
125
130
|
|
|
126
|
-
Full DEPS.yml schema:
|
|
131
|
+
Full {Colors.byellow}DEPS.yml{Colors.normal}{Colors.yellow} schema:
|
|
127
132
|
|
|
128
133
|
```
|
|
129
134
|
DEFAULTS: # <table> defaults applied to ALL targets in this file, local targets ** override ** the defaults.
|
|
@@ -140,6 +145,14 @@ target-spec:
|
|
|
140
145
|
SOME_DEFINE: value
|
|
141
146
|
SOME_DEFINE_NO_VALUE: # we just leave this blank, or use nil (yaml's None)
|
|
142
147
|
|
|
148
|
+
plusargs: # <table>
|
|
149
|
+
variable0: value
|
|
150
|
+
variable1: # blank for no value, or use nil (yaml's None)
|
|
151
|
+
|
|
152
|
+
parameters: # <table>
|
|
153
|
+
SomeParameter: value
|
|
154
|
+
SOME_OTHER_PARAMETER: value
|
|
155
|
+
|
|
143
156
|
incdirs: # <array>
|
|
144
157
|
- some/relative/path
|
|
145
158
|
|
|
@@ -150,20 +163,22 @@ target-spec:
|
|
|
150
163
|
- some_file.sv # <string> aka, a file
|
|
151
164
|
- sv@some_file.txt # <string> aka, ext@file where we'd like a file not ending in .sv to be
|
|
152
165
|
# treated as a .sv file for tools.
|
|
153
|
-
# Supported for sv@, v@, vhdl@, cpp@
|
|
166
|
+
# Supported for sv@, v@, vhdl@, cpp@, sdc@, f@, py@, makefile@
|
|
154
167
|
- commands: # <table> with key 'commands' for a <array>: support for built-in commands
|
|
155
168
|
# Note this cannot be confused for other targets or files.
|
|
156
169
|
- shell: # <string>
|
|
157
|
-
var-subst-args: # <bool> default false. If true, substitute vars in commands, such as {fpga}
|
|
158
|
-
# substituted from eda arg --fpga=SomeFpga, such that {fpga} becomes SomeFpga
|
|
170
|
+
var-subst-args: # <bool> default false. If true, substitute vars in commands, such as {{fpga}}
|
|
171
|
+
# substituted from eda arg --fpga=SomeFpga, such that {{fpga}} becomes SomeFpga
|
|
159
172
|
var-subst-os-env: #<bool> default false. If true, substitute vars in commands using os.environ vars,
|
|
160
|
-
# such as {FPGA} could get substituted by env value for $FPGA
|
|
161
|
-
tee: # <string> optional filename, otherwise shell commands write to {target-spec}__shell_0.log
|
|
173
|
+
# such as {{FPGA}} could get substituted by env value for $FPGA
|
|
174
|
+
tee: # <string> optional filename, otherwise shell commands write to {{target-spec}}__shell_0.log
|
|
162
175
|
run-from-work-dir: #<bool> default true. If false, runs from the directory of this DEPS file.
|
|
163
176
|
filepath-subst-target-dir: #<bool> default true. If false, disables shell file path
|
|
164
177
|
substituion on this target's directory (this DEPS file dir).
|
|
165
178
|
dirpath-subst-target-dir: #<bool> default false. If true, enables shell directory path
|
|
166
179
|
substituion on this target's directory (this DEPS file dir).
|
|
180
|
+
run-after-tool: # <bool> default false. Set to true to run after any EDA tools, or
|
|
181
|
+
any command handlers have completed.
|
|
167
182
|
- shell: echo "Hello World!"
|
|
168
183
|
- work-dir-add-sources: # <array or | space separated string>, this is how to add generated files
|
|
169
184
|
# to compile order list.
|
|
@@ -196,6 +211,8 @@ target-spec:
|
|
|
196
211
|
args: # <array or | space separated string>
|
|
197
212
|
deps: # <array or | space separated string> # Note: not implemented yet
|
|
198
213
|
defines: ## <table>
|
|
214
|
+
plusargs: ## <table>
|
|
215
|
+
parameters: ## <table>
|
|
199
216
|
incdirs: ## <array>
|
|
200
217
|
|
|
201
218
|
tags: # <table> this is the currently support tags features in a target.
|
|
@@ -215,6 +232,8 @@ target-spec:
|
|
|
215
232
|
# tool in 'with-tools'.
|
|
216
233
|
deps: <array or | space separated string, applied with tag>
|
|
217
234
|
defines: <table, applied with tag>
|
|
235
|
+
plusargs: <table, applied with tag>
|
|
236
|
+
parameters: <table, applied with tag>
|
|
218
237
|
incdirs: <array, applied with tag>
|
|
219
238
|
replace-config-tools: <table> # spec matching eda_config_defaults.yml::tools.<tool> (replace merge strategy)
|
|
220
239
|
additive-config-tools: <table> # spec matching eda_config_defaults.yml::tools.<tool> (additive merge strategy)
|
|
@@ -300,7 +300,6 @@ class CommandSim(CommandDesign): # pylint: disable=too-many-public-methods
|
|
|
300
300
|
tool = self.args.get('tool', None)
|
|
301
301
|
# Certain args are allow-listed here
|
|
302
302
|
deps_file_args = []
|
|
303
|
-
print(f'SUPER DREW DEBUG: {self.get_command_line_args()=}')
|
|
304
303
|
for a in self.get_command_line_args():
|
|
305
304
|
if any(a.startswith(x) for x in [
|
|
306
305
|
'--compile-args',
|
|
@@ -16,7 +16,7 @@ from opencos.util import debug, error
|
|
|
16
16
|
from opencos.utils.markup_helpers import yaml_safe_load, toml_load_only_root_line_numbers, \
|
|
17
17
|
markup_writer, markup_dumper
|
|
18
18
|
from opencos.utils.str_helpers import fnmatch_or_re, dep_str2list, pretty_list_columns_manual, \
|
|
19
|
-
is_valid_target_name, VALID_TARGET_INFO_STR
|
|
19
|
+
is_valid_target_name, VALID_TARGET_INFO_STR, get_shorter_path_str_rel_vs_abs
|
|
20
20
|
from opencos.utils.subprocess_helpers import subprocess_run_background
|
|
21
21
|
from opencos.utils.status_constants import EDA_DEPS_FILE_NOT_FOUND, EDA_DEPS_TARGET_NOT_FOUND
|
|
22
22
|
|
|
@@ -270,9 +270,12 @@ class DepsFile:
|
|
|
270
270
|
return f'line={self.line_numbers.get(target_node, "")}'
|
|
271
271
|
|
|
272
272
|
def gen_caller_info(self, target: str) -> str:
|
|
273
|
-
'''Given a full target name (path/to/my_target) return caller_info str for debug
|
|
273
|
+
'''Given a full target name (path/to/my_target) return caller_info str for debug
|
|
274
|
+
|
|
275
|
+
Use abspath if the str is shorter, for the path information part.
|
|
276
|
+
'''
|
|
274
277
|
return '::'.join([
|
|
275
|
-
self.rel_deps_file,
|
|
278
|
+
get_shorter_path_str_rel_vs_abs(rel_path=self.rel_deps_file),
|
|
276
279
|
target,
|
|
277
280
|
self.get_approx_line_number_str(target)
|
|
278
281
|
])
|
|
@@ -298,90 +301,90 @@ class DepsFile:
|
|
|
298
301
|
some caller_info(str). This is more useful for YAML or TOML markup where we have
|
|
299
302
|
caller_info.
|
|
300
303
|
'''
|
|
301
|
-
if target_node not in self.data:
|
|
302
|
-
found_target = False
|
|
303
304
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
return False
|
|
305
|
+
if target_node in self.data:
|
|
306
|
+
debug(f'Found {target_node=} in deps_file={self.rel_deps_file}')
|
|
307
|
+
return True
|
|
308
308
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
t_path = ''
|
|
314
|
-
t_node = target_node
|
|
315
|
-
t_full = os.path.join(t_path, t_node)
|
|
309
|
+
if target_node.startswith('-'):
|
|
310
|
+
# likely an unparsed arg that made it this far.
|
|
311
|
+
util.warning(f"Ignoring unparsed argument '{target_node}'")
|
|
312
|
+
return False
|
|
316
313
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
314
|
+
# For error printing, prefer relative paths, unless the abspath is shorter:
|
|
315
|
+
if self.target_path:
|
|
316
|
+
t_path = os.path.relpath(self.target_path) + os.path.sep
|
|
317
|
+
t_path = get_shorter_path_str_rel_vs_abs(rel_path=t_path)
|
|
318
|
+
else:
|
|
319
|
+
t_path = ''
|
|
320
|
+
t_node = target_node
|
|
321
|
+
t_full = os.path.join(t_path, t_node)
|
|
321
322
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
self.error_ifarg(
|
|
327
|
-
f'Trying to resolve command-line target={t_full} (file?):',
|
|
328
|
-
f'File={t_node} not found in directory={t_path}',
|
|
329
|
-
arg='error-unknown-args',
|
|
330
|
-
error_code=EDA_DEPS_FILE_NOT_FOUND
|
|
331
|
-
)
|
|
332
|
-
elif not self.rel_deps_file:
|
|
333
|
-
# target, but there's no DEPS file
|
|
334
|
-
self.error_ifarg(
|
|
335
|
-
f'Trying to resolve command-line target={t_full}:',
|
|
336
|
-
f'but path {t_path} has no DEPS markup file (DEPS.yml)',
|
|
337
|
-
arg='error-unknown-args',
|
|
338
|
-
error_code=EDA_DEPS_FILE_NOT_FOUND
|
|
339
|
-
)
|
|
340
|
-
else:
|
|
341
|
-
self.warning_show_available_targets()
|
|
342
|
-
self.error_ifarg(
|
|
343
|
-
f'Trying to resolve command-line target={t_full}:',
|
|
344
|
-
f'was not found in deps_file={self.rel_deps_file}',
|
|
345
|
-
arg='error-unknown-args',
|
|
346
|
-
error_code=EDA_DEPS_TARGET_NOT_FOUND
|
|
347
|
-
)
|
|
323
|
+
if not is_valid_target_name(target_node):
|
|
324
|
+
util.warning(
|
|
325
|
+
f"In file {self.rel_deps_file}, {target_node} {VALID_TARGET_INFO_STR}"
|
|
326
|
+
)
|
|
348
327
|
|
|
328
|
+
if not caller_info:
|
|
329
|
+
# If we don't have caller_info, likely came from command line (or DEPS JSON data):
|
|
330
|
+
if '.' in target_node:
|
|
331
|
+
# Likely a filename (target_node does not include path)
|
|
332
|
+
self.error_ifarg(
|
|
333
|
+
f'Trying to resolve command-line target={t_full} (file?):',
|
|
334
|
+
f'File={t_node} not found in directory={t_path}',
|
|
335
|
+
arg='error-unknown-args',
|
|
336
|
+
error_code=EDA_DEPS_FILE_NOT_FOUND
|
|
337
|
+
)
|
|
338
|
+
elif not self.rel_deps_file:
|
|
339
|
+
# target, but there's no DEPS file
|
|
340
|
+
self.error_ifarg(
|
|
341
|
+
f'Trying to resolve command-line target={t_full}:',
|
|
342
|
+
f'but path {t_path} has no DEPS markup file (DEPS.yml)',
|
|
343
|
+
arg='error-unknown-args',
|
|
344
|
+
error_code=EDA_DEPS_FILE_NOT_FOUND
|
|
345
|
+
)
|
|
349
346
|
else:
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
f'File={t_node} not found in directory={t_path}',
|
|
359
|
-
arg='error-unknown-args',
|
|
360
|
-
error_code=EDA_DEPS_FILE_NOT_FOUND
|
|
361
|
-
)
|
|
362
|
-
elif not self.rel_deps_file:
|
|
363
|
-
# target, but there's no DEPS file
|
|
364
|
-
self.error_ifarg(
|
|
365
|
-
f'Trying to resolve target={t_full}:',
|
|
366
|
-
f'called from {caller_info},',
|
|
367
|
-
f'but {t_path} has no DEPS markup file (DEPS.yml)',
|
|
368
|
-
arg='error-unknown-args',
|
|
369
|
-
error_code=EDA_DEPS_FILE_NOT_FOUND
|
|
370
|
-
)
|
|
371
|
-
else:
|
|
372
|
-
self.warning_show_available_targets()
|
|
373
|
-
self.error_ifarg(
|
|
374
|
-
f'Trying to resolve target={t_full}:',
|
|
375
|
-
f'called from {caller_info},',
|
|
376
|
-
f'Target not found in deps_file={self.rel_deps_file}',
|
|
377
|
-
arg='error-unknown-args',
|
|
378
|
-
error_code=EDA_DEPS_TARGET_NOT_FOUND
|
|
379
|
-
)
|
|
347
|
+
self.warning_show_available_targets()
|
|
348
|
+
self.error_ifarg(
|
|
349
|
+
f'Trying to resolve command-line target={t_full}:',
|
|
350
|
+
f'was not found in deps_file={self.rel_deps_file}',
|
|
351
|
+
arg='error-unknown-args',
|
|
352
|
+
error_code=EDA_DEPS_TARGET_NOT_FOUND
|
|
353
|
+
)
|
|
354
|
+
|
|
380
355
|
else:
|
|
381
|
-
|
|
382
|
-
|
|
356
|
+
# If we have caller_info, then this was a recursive call from another
|
|
357
|
+
# DEPS file. It should already have the useful error messaging:
|
|
358
|
+
|
|
359
|
+
if '.' in target_node:
|
|
360
|
+
# Likely a filename (target_node does not include path)
|
|
361
|
+
self.error_ifarg(
|
|
362
|
+
f'Trying to resolve target={t_full} (file?):',
|
|
363
|
+
f'called from {caller_info},',
|
|
364
|
+
f'File={t_node} not found in directory={t_path}',
|
|
365
|
+
arg='error-unknown-args',
|
|
366
|
+
error_code=EDA_DEPS_FILE_NOT_FOUND
|
|
367
|
+
)
|
|
368
|
+
elif not self.rel_deps_file:
|
|
369
|
+
# target, but there's no DEPS file
|
|
370
|
+
self.error_ifarg(
|
|
371
|
+
f'Trying to resolve target={t_full}:',
|
|
372
|
+
f'called from {caller_info},',
|
|
373
|
+
f'but {t_path} has no DEPS markup file (DEPS.yml)',
|
|
374
|
+
arg='error-unknown-args',
|
|
375
|
+
error_code=EDA_DEPS_FILE_NOT_FOUND
|
|
376
|
+
)
|
|
377
|
+
else:
|
|
378
|
+
self.warning_show_available_targets()
|
|
379
|
+
self.error_ifarg(
|
|
380
|
+
f'Trying to resolve target={t_full}:',
|
|
381
|
+
f'called from {caller_info},',
|
|
382
|
+
f'Target not found in deps_file={self.rel_deps_file}',
|
|
383
|
+
arg='error-unknown-args',
|
|
384
|
+
error_code=EDA_DEPS_TARGET_NOT_FOUND
|
|
385
|
+
)
|
|
383
386
|
|
|
384
|
-
return
|
|
387
|
+
return False
|
|
385
388
|
|
|
386
389
|
|
|
387
390
|
def get_entry(self, target_node) -> dict:
|
|
@@ -204,9 +204,12 @@ def auto_tool_setup( # pylint: disable=too-many-locals,too-many-branches,too-man
|
|
|
204
204
|
|
|
205
205
|
has_all_exe = True
|
|
206
206
|
has_all_in_exe_path = True
|
|
207
|
+
exe_path = None
|
|
207
208
|
for exe in exe_list:
|
|
208
209
|
assert exe != '', f'{name=} {value=} value missing "exe" {exe=}'
|
|
209
210
|
p = shutil.which(exe)
|
|
211
|
+
if not exe_path:
|
|
212
|
+
exe_path = p # set on first required exe
|
|
210
213
|
if not p:
|
|
211
214
|
has_all_exe = False
|
|
212
215
|
util.debug(f"... No, missing exe {exe}")
|
|
@@ -217,10 +220,11 @@ def auto_tool_setup( # pylint: disable=too-many-locals,too-many-branches,too-man
|
|
|
217
220
|
|
|
218
221
|
has_vsim_helper = True
|
|
219
222
|
if value.get('requires_vsim_helper', False):
|
|
220
|
-
# This tool name must be in opencos.utils.vsim_helper.
|
|
223
|
+
# This tool name must be in opencos.utils.vsim_helper.TOOL_PATH[name].
|
|
221
224
|
# Special case for vsim being used by a lot of tools.
|
|
222
225
|
vsim_helper.init() # only runs checks once internally
|
|
223
|
-
|
|
226
|
+
exe_path = vsim_helper.TOOL_PATH[name]
|
|
227
|
+
has_vsim_helper = bool(exe_path)
|
|
224
228
|
|
|
225
229
|
has_vscode_helper = True
|
|
226
230
|
needs_vscode_extensions = value.get('requires_vscode_extension', None)
|
|
@@ -254,18 +258,24 @@ def auto_tool_setup( # pylint: disable=too-many-locals,too-many-branches,too-man
|
|
|
254
258
|
|
|
255
259
|
if all((has_all_py, has_all_env, has_all_exe, has_all_in_exe_path,
|
|
256
260
|
has_vsim_helper, has_vscode_helper)):
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
261
|
+
if exe_path:
|
|
262
|
+
p = exe_path
|
|
263
|
+
else:
|
|
264
|
+
p = shutil.which(exe_list[0])
|
|
265
|
+
config['auto_tools_found'][name] = p # populate key-value pairs w/ first exe in list
|
|
260
266
|
if not quiet:
|
|
261
267
|
util.info(f"Detected {name} ({p})")
|
|
262
|
-
tool_setup(
|
|
268
|
+
tool_setup(
|
|
269
|
+
tool=name, quiet=True, auto_setup=True, warnings=warnings, config=config
|
|
270
|
+
)
|
|
263
271
|
|
|
264
272
|
return config
|
|
265
273
|
|
|
266
274
|
|
|
267
|
-
def tool_setup(
|
|
268
|
-
|
|
275
|
+
def tool_setup(
|
|
276
|
+
tool: str, config: dict, quiet: bool = False, auto_setup: bool = False,
|
|
277
|
+
warnings: bool = True
|
|
278
|
+
):
|
|
269
279
|
''' Adds items to config["tools_loaded"] (set) and updates config['command_handler'].
|
|
270
280
|
|
|
271
281
|
config is potentially updated for entry ['command_handler'][command] with a Tool class.
|
|
@@ -613,9 +623,36 @@ def main(*args):
|
|
|
613
623
|
util.global_log.stop()
|
|
614
624
|
return main_ret
|
|
615
625
|
|
|
626
|
+
def main_show_autocomplete_instructions() -> None:
|
|
627
|
+
''' Executable script entry point - eda_show_autocomplete
|
|
628
|
+
|
|
629
|
+
from pyproject.toml::project.scripts. Shows instructions on how to enable bash autocomplete
|
|
630
|
+
'''
|
|
631
|
+
source_filepath = opencos.__file__.replace(
|
|
632
|
+
'__init__.py', 'eda_deps_bash_completion.bash'
|
|
633
|
+
)
|
|
634
|
+
if os.path.exists(source_filepath):
|
|
635
|
+
print(
|
|
636
|
+
f"{Colors.yellow}To enable bash autocompletion with"
|
|
637
|
+
f" {Colors.bold}eda{Colors.normal}{Colors.yellow} script (uv not equired):"
|
|
638
|
+
)
|
|
639
|
+
print(f"{Colors.normal}")
|
|
640
|
+
print(f" source {source_filepath}")
|
|
641
|
+
print("")
|
|
642
|
+
print(f"{Colors.yellow}Feel free to inspect this script prior to sourcing.")
|
|
643
|
+
print(f"{Colors.normal}")
|
|
644
|
+
sys.exit(0)
|
|
645
|
+
else:
|
|
646
|
+
util.error(f"It appears the following file(s) doe not exist: {source_filepath}")
|
|
647
|
+
sys.exit(1)
|
|
648
|
+
|
|
616
649
|
|
|
617
650
|
def main_cli() -> None:
|
|
618
|
-
'''
|
|
651
|
+
''' Executable script entry point - eda
|
|
652
|
+
|
|
653
|
+
from pyproject.tom::project.scripts, or from __main__.
|
|
654
|
+
Returns None, will exit with return code.
|
|
655
|
+
'''
|
|
619
656
|
signal.signal(signal.SIGINT, signal_handler)
|
|
620
657
|
util.global_exit_allowed = True
|
|
621
658
|
# Strip eda or eda.py from sys.argv, we know who we are if called from __main__:
|
|
@@ -45,6 +45,9 @@ def print_base_help() -> None:
|
|
|
45
45
|
def print_eda_usage_line(no_targets: bool = False, command_name='COMMAND') -> None:
|
|
46
46
|
'''Prints line for eda [options] COMMAND [options] FILES|TARGETS,...'''
|
|
47
47
|
print(f'{safe_emoji("🔦 ")}Usage:')
|
|
48
|
+
print(f' {Colors.bold}{Colors.yellow}eda_targets PATTERN')
|
|
49
|
+
print(f' {Colors.bold}{Colors.yellow}eda_show_autocomplete{Colors.normal}')
|
|
50
|
+
print()
|
|
48
51
|
if no_targets:
|
|
49
52
|
print(
|
|
50
53
|
(f' {Colors.bold}{Colors.yellow}eda {Colors.cyan}[options]'
|
|
@@ -208,11 +211,12 @@ class Tool:
|
|
|
208
211
|
def set_exe(self, config: dict) -> None:
|
|
209
212
|
'''Sets self._EXE based on config'''
|
|
210
213
|
if self._TOOL and self._TOOL in config.get('auto_tools_order', [{}])[0]:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
exe = exe[0] # pick first
|
|
214
|
+
# config['auto_tools_found'] has the first exe full path:
|
|
215
|
+
exe = config.get('auto_tools_found', {}).get(self._TOOL)
|
|
214
216
|
if exe and exe != self._EXE:
|
|
215
|
-
|
|
217
|
+
# Note that shutil.which() on the exe leaf may not match, this does NOT
|
|
218
|
+
# modify os.environ['PATH'].
|
|
219
|
+
util.debug(f'{self._TOOL} using exe: {exe}')
|
|
216
220
|
self._EXE = exe
|
|
217
221
|
|
|
218
222
|
def get_tool_name(self) -> str:
|
|
@@ -390,11 +390,18 @@ def tool_try_add_to_path( # pylint: disable=too-many-branches
|
|
|
390
390
|
util.error(f'--tool setting for {tool}: {user_exe} is not an executable')
|
|
391
391
|
return name
|
|
392
392
|
|
|
393
|
-
user_exe = shutil.which(
|
|
393
|
+
user_exe = shutil.which(user_exe)
|
|
394
394
|
|
|
395
395
|
if update_config:
|
|
396
396
|
if isinstance(config_exe, list):
|
|
397
397
|
config['auto_tools_order'][0][name]['exe'][0] = user_exe
|
|
398
|
+
for index,value in enumerate(config_exe[1:]):
|
|
399
|
+
# update all entries, if we can, if the value is also in 'path'
|
|
400
|
+
# from our set --tool=Name=path/exe
|
|
401
|
+
new_value = os.path.join(path, os.path.split(value)[1])
|
|
402
|
+
if os.path.exists(new_value) and shutil.which(new_value) and \
|
|
403
|
+
os.access(new_value, os.X_OK):
|
|
404
|
+
config['auto_tools_order'][0][name]['exe'][index] = new_value
|
|
398
405
|
else:
|
|
399
406
|
config['auto_tools_order'][0][name]['exe'] = user_exe
|
|
400
407
|
util.debug(f'For {tool=}, auto_tools_order config updated')
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# How to use?
|
|
4
|
+
# 1) run:
|
|
5
|
+
# eda_show_autocomplete
|
|
6
|
+
# for instructions, will likely show you the location of this file,
|
|
7
|
+
# eda_deps_bash_completion.bash, for you to source. Does not require uv.
|
|
8
|
+
#
|
|
9
|
+
# 2) Given the result from (1), and if you use uv, add the following to your
|
|
10
|
+
# ~/.bashrc:
|
|
11
|
+
# # Make sure 'eda' is a valid executable when not in a venv:
|
|
12
|
+
# if ! type -P "eda" &>/dev/null; then
|
|
13
|
+
# uv tool install --python 3.14 opencos-eda >/dev/null 2>&1
|
|
14
|
+
# echo "uv tool installed opencos-eda"
|
|
15
|
+
# fi
|
|
16
|
+
# if [ -f PATH-FROM-STEP-1 ]; then
|
|
17
|
+
# . PATH-FROM-STEP-1
|
|
18
|
+
# fi
|
|
19
|
+
#
|
|
20
|
+
# 3) copy this script locally and source it.
|
|
21
|
+
# For example:
|
|
22
|
+
# > source ~/sh/eda_deps_bash_completion.bash
|
|
23
|
+
# You can put this in your .bashrc. Note you will need a venv active or
|
|
24
|
+
# "eda" isn't in your path yet.
|
|
25
|
+
#
|
|
26
|
+
# 4) Have it sourced when you start your venv. Note this doesn't play as nicely
|
|
27
|
+
# with "uv" due to having a less stable .venv, but you can add this to your
|
|
28
|
+
# VENV_NAME/bin/activate script:
|
|
29
|
+
# (bottom of activate script, assuming python3.XX):
|
|
30
|
+
# script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
|
31
|
+
# . $script_dir/../lib/python3.XX/site-packages/opencos/eda_deps_bash_completion.bash
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# scripts via pyproject.toml:
|
|
35
|
+
# what we want to add target completion to:
|
|
36
|
+
SCRIPT_NAME="eda"
|
|
37
|
+
# how we get the completion targets:
|
|
38
|
+
EXTRACTION_SCRIPT_NAME="eda_targets"
|
|
39
|
+
|
|
40
|
+
EDA_WORDS="sim lint elab synth flist proj multi tools-multi sweep build \
|
|
41
|
+
waves upload open export shell targets lec \
|
|
42
|
+
+define+ +incdirs+ \
|
|
43
|
+
--help --quiet --verbose --debug \
|
|
44
|
+
--tool --seed --top --keep --force --fake --lint --work-dir \
|
|
45
|
+
--stop-before-compile --stop-after-compile --stop-before-elaborate \
|
|
46
|
+
--export --export-run --export-json \
|
|
47
|
+
"
|
|
48
|
+
|
|
49
|
+
_eda_script_completion() {
|
|
50
|
+
|
|
51
|
+
# Set up for additional completions
|
|
52
|
+
local cur="${COMP_WORDS[COMP_CWORD]}"
|
|
53
|
+
|
|
54
|
+
# If we have a DEPS markup file and the current word starts with a key indicator
|
|
55
|
+
local completions=""
|
|
56
|
+
local keys=""
|
|
57
|
+
if [[ $(type -P "$EXTRACTION_SCRIPT_NAME") ]]; then
|
|
58
|
+
keys=$("$EXTRACTION_SCRIPT_NAME" "$cur")
|
|
59
|
+
if [[ -n "$keys" ]]; then
|
|
60
|
+
completions=($(compgen -W "$keys $EDA_WORDS" -- "$cur"))
|
|
61
|
+
fi
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
if [ -z "${completions}" ]; then
|
|
65
|
+
# If we didn't find anything in a DEPS.[yml|yaml|toml|json], then use:
|
|
66
|
+
# -- a bunch of known eda words or args.
|
|
67
|
+
# 2. a glob the current word to mimic normal bash:
|
|
68
|
+
completions=($(compgen -W "$EDA_WORDS" -G "${cur}*" -- "$cur"))
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
COMPREPLY=("${completions[@]}")
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
if [[ $(type -P "$EXTRACTION_SCRIPT_NAME") ]]; then
|
|
76
|
+
complete -F _eda_script_completion "$SCRIPT_NAME"
|
|
77
|
+
fi
|
|
@@ -25,7 +25,7 @@ class ToolQuesta(Tool):
|
|
|
25
25
|
_EXE = 'vsim'
|
|
26
26
|
|
|
27
27
|
starter_edition = False
|
|
28
|
-
use_vopt =
|
|
28
|
+
use_vopt = False # set manually or by get_versions() (after __init__ has set self._EXE)
|
|
29
29
|
sim_exe = '' # vsim or qrun
|
|
30
30
|
sim_exe_base_path = ''
|
|
31
31
|
questa_major = None
|
|
@@ -33,7 +33,6 @@ class ToolQuesta(Tool):
|
|
|
33
33
|
|
|
34
34
|
def __init__(self, config: dict):
|
|
35
35
|
super().__init__(config=config)
|
|
36
|
-
self.args['part'] = 'xcu200-fsgd2104-2-e'
|
|
37
36
|
|
|
38
37
|
def get_versions(self) -> str:
|
|
39
38
|
if self._VERSION:
|
|
@@ -30,6 +30,7 @@ class ToolVerilator(Tool):
|
|
|
30
30
|
def get_versions(self) -> str:
|
|
31
31
|
if self._VERSION:
|
|
32
32
|
return self._VERSION
|
|
33
|
+
# __init__ would have set self.EXE to full path.
|
|
33
34
|
path = shutil.which(self._EXE)
|
|
34
35
|
if not path:
|
|
35
36
|
self.error(f'"{self._EXE}" not in path or not installed, see {self._URL})')
|
|
@@ -203,3 +203,10 @@ def strip_ansi_color(text: str) -> str:
|
|
|
203
203
|
'''Strip ANSI color characters from str'''
|
|
204
204
|
ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
|
|
205
205
|
return ansi_escape.sub('', text)
|
|
206
|
+
|
|
207
|
+
def get_shorter_path_str_rel_vs_abs(rel_path: str) -> str:
|
|
208
|
+
'''Returns the shorter of relative path (input arg) vs abspath (converted)'''
|
|
209
|
+
apath = os.path.abspath(rel_path)
|
|
210
|
+
if len(apath) < len(rel_path):
|
|
211
|
+
return apath
|
|
212
|
+
return rel_path
|