Skip to content

Commit 9f801fd

Browse files
authored
Workflows: Support recursive directories (#795)
* Fix workflow files without path On commit f909009 the workflow code was cleaned up, but it broke files that had no `path`. Error shown is similar to this: ``` destdir = f"{destdir}/{os.path.dirname(entry['origin'])}" ^^^^^^^ UnboundLocalError: cannot access local variable 'destdir' where it is not associated with a value ``` That's because in the previously mentioned commit variable `default_destdir` that was removed was accidentally changed to `destdir` instead of `outputdir`. This patch fixes this problem using the right variable. * Workflows: Support recursive directories Current workflow code only supports files within a single directory. This patch adds the functionality to support recursive directories, so a workflow like this: ``` ctrlplane: type: workflow destdir: ./out scripts: - scripts/ctrlplane.sh files: - origin: ctrl ``` Will work with the file structure: ``` ├── ctrl │   ├── 00-openstack-ns.yaml │   ├── 00-operators │   │   ├── 00-operator-cert-manager.yaml │   │   ├── 00-operator-cluster-observability.yam │   │   ├── 00-operator-metallb.yaml │   │   ├── 00-operator-nmstate.yaml │   │   └── 00-operator-openstack.yaml ```
1 parent ed8148b commit 9f801fd

File tree

3 files changed

+82
-13
lines changed

3 files changed

+82
-13
lines changed

docs/index.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,6 +1344,38 @@ Will create the following file structure:
13441344
./outdir/frout.j2
13451345
```
13461346

1347+
When using a directory in a `files` section the structure will be recreated and all files within it will be rendered.
1348+
1349+
If we have this file structure:
1350+
1351+
```
1352+
./arch/frout.sh
1353+
./arch/frout.txt
1354+
./arch/frout.j2
1355+
./arch/subdir/anotherfile.sh
1356+
```
1357+
1358+
And we use this workflow:
1359+
1360+
```YAML
1361+
myworkflow:
1362+
type: workflow
1363+
destdir: outdir
1364+
scripts:
1365+
- arch/frout.sh
1366+
files:
1367+
- origin: arch
1368+
```
1369+
1370+
We'll end up with the following:
1371+
1372+
```
1373+
./outdir/frout.sh
1374+
./outdir/arch/frout.txt
1375+
./outdir/arch/frout.j2
1376+
./outdir/arch/subdir/anotherfile.sh
1377+
```
1378+
13471379
### vms
13481380
You can point at an existing profile in your plans, define all parameters for the vms, or combine both approaches. You can even add your own profile definitions in the plan file and reference them within the same plan:
13491381

docs/index.rst

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,6 +1446,40 @@ Will create the following file structure:
14461446
./outdir/frout.txt
14471447
./outdir/frout.j2
14481448

1449+
1450+
When using a directory in a ``files`` section the structure will be recreated and all files within it will be rendered.
1451+
1452+
If we have this file structure:
1453+
1454+
::
1455+
1456+
./arch/frout.sh
1457+
./arch/frout.txt
1458+
./arch/frout.j2
1459+
./arch/subdir/anotherfile.sh
1460+
1461+
1462+
And we use this workflow:
1463+
1464+
.. code:: yaml
1465+
1466+
myworkflow:
1467+
type: workflow
1468+
destdir: outdir
1469+
scripts:
1470+
- arch/frout.sh
1471+
files:
1472+
- origin: arch
1473+
1474+
We'll end up with the following:
1475+
1476+
::
1477+
1478+
./outdir/frout.sh
1479+
./outdir/arch/frout.txt
1480+
./outdir/arch/frout.j2
1481+
./outdir/arch/subdir/anotherfile.sh
1482+
14491483
vms
14501484
~~~
14511485

kvirt/baseconfig.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,29 +1212,32 @@ def create_workflow(self, workflow, overrides={}, outputdir=None, run=True, base
12121212
if 'path' in entry:
12131213
destdir = os.path.dirname(entry['path'])
12141214
else:
1215-
destdir = f"{destdir}/{os.path.dirname(entry['origin'])}"
1215+
destdir = f"{outputdir}/{os.path.dirname(entry['origin'])}"
12161216
if not os.path.exists(destdir):
12171217
pprint(f"Creating directory {destdir}")
12181218
os.makedirs(destdir)
1219-
content = entry.get('content')
1220-
render = entry.get('render', True)
1221-
if isinstance(render, str):
1222-
render = render.lower() == 'true'
1223-
if origin in directories:
1219+
# If we've already processed the directory tree then there's no
1220+
# point in looking at individual files.
1221+
if any(origin.startswith(d) for d in directories):
12241222
continue
12251223
elif not os.path.exists(origin):
12261224
msg = f"Origin file {origin} not found"
12271225
error(msg)
12281226
return {'result': 'failure', 'reason': msg}
12291227
elif os.path.isdir(origin):
1230-
origin = entry.get('origin')
1231-
if not os.path.exists(f"{destdir}/{os.path.basename(origin)}"):
1232-
pprint(f"Creating directory {destdir}/{os.path.basename(origin)}")
1233-
os.makedirs(f"{destdir}/{os.path.basename(origin)}")
1234-
directories.append(origin)
1235-
for _fic in os.listdir(origin):
1236-
directoryfiles.append(f'{origin}/{_fic}')
1228+
for path, _, files in os.walk(origin):
1229+
new_destdir = f"{destdir}{path}"
1230+
if not os.path.exists(new_destdir):
1231+
pprint(f"Creating directory {new_destdir}")
1232+
os.makedirs(new_destdir)
1233+
directories.append(path)
1234+
for _fic in files:
1235+
directoryfiles.append(f'{path}/{_fic}')
12371236
continue
1237+
content = entry.get('content')
1238+
render = entry.get('render', True)
1239+
if isinstance(render, str):
1240+
render = render.lower() == 'true'
12381241
filename = os.path.basename(origin)
12391242
if not render:
12401243
content = open(origin, 'r').read()

0 commit comments

Comments
 (0)