11#!/usr/bin/env python3
22
3- import subprocess
4- import os
5- import re
63from tplgtool import TplgParser , TplgFormatter
74from common import format_pipeline , export_pipeline
85
@@ -117,6 +114,7 @@ def loadFile(self, filename, sofcard=0):
117114 pipeline [comp ] = interweaved_dict [comp ]
118115 return 0
119116
117+ # The following functions re-implement built-in Python sets
120118 @staticmethod
121119 def list_and (lst1 , lst2 ):
122120 assert (lst1 is not None and lst2 is not None )
@@ -164,10 +162,22 @@ def setField(self, field_lst):
164162 def setBlock (self , block_lst = None ):
165163 self ._block_lst = block_lst
166164
167- def _filterOutput (self , target_lst , filter_dict , bIn ):
165+ def _filterOutput (self , pipelines , filter_dict , bIn ):
166+ """Returns the subset of pipelines matching a single filter expression.
167+
168+ pipelines: list of pipelines. Each pipeline is a dict, example:
169+ {'cap_name': 'Low Latency Playback 0', 'dev': 'hw:0,6',...
170+
171+ filter_dict: filter like for instance { 'id' : ['3'] }. It's not
172+ clear what happens if the dict has several elements; avoid?
173+
174+ bIn: True: exclude filter, False: include filter.
175+ """
168176 filtered = []
169- for line in target_lst [:]:
170- check = False
177+ for line in pipelines [:]:
178+ check = False # "check" means "match"
179+ # This inner for loop is deceiving: the filter_dict usually has a
180+ # single key:value and then the break/else is pure confusion.
171181 for key , value in filter_dict .items ():
172182 if 'any' in value or value == ['' ]:
173183 check = True if key in line .keys () else False
@@ -177,21 +187,25 @@ def _filterOutput(self, target_lst, filter_dict, bIn):
177187 if check is bIn :
178188 break
179189 else :
190+ # No 'break': include this pipeline
180191 filtered .append (line )
181192 return filtered
182193
183194 def _filter_by_dict (self , filter_dict ):
195+ "filter_dict comes from parse_filter(), see filter_dict example there."
184196 if filter_dict == {}:
185197 return self ._pipeline_lst
186198 full_list = self ._pipeline_lst
187199 filtered = None
188- # pipelines filtered by the first filter item
200+ # Apply the first expression in the filter
189201 for key , value in filter_dict ['filter' ][0 ].items ():
190202 if key .startswith ('~' ):
191203 filtered = self ._filterOutput (full_list , {key [1 :]:value }, True )
192204 else :
193205 filtered = self ._filterOutput (full_list , {key :value }, False )
194- # do filtering by the rest filter items and logic operations
206+ # Combine with the remaining expressions and boolean
207+ # operators. Apply the filters from left to right, no usual
208+ # boolean precedence. See --help below.
195209 for idx in range (1 , len (filter_dict ['filter' ])):
196210 new_filtered = None
197211 for key , value in filter_dict ['filter' ][idx ].items ():
@@ -251,9 +265,15 @@ def func_getPipeline(tplgObj, tplgName, sdcard_id, sort):
251265 exit (1 )
252266 return tplgObj .getPipeline (sort )
253267
254- # parse filter string into two structures, one is dict list for each filter item,
255- # and another is logic operation list.
256268 def parse_filter (filter_str ):
269+ """Parse filter input into two structures, one is dict list for each
270+ filter item, and another is logic operation list. For example
271+ "id:2 | pga & id:1" is parsed as:
272+
273+ { 'filter': [ {'id': ['2']}, {'pga': ['']}, {'id': ['1']} ],
274+ 'op': [ '|', '&' ]
275+ }
276+ """
257277 filter_lst = []
258278 op_lst = []
259279 for filter_elem in filter_str .split ('|' ):
@@ -285,12 +305,21 @@ def parse_and_set_block_keyword(block_str, tplgreader):
285305string format is 'key':'value','value', the filter
286306string support & | and ~ logic operation.
287307if only care about key, you can use 'key':'any'.
308+
288309Example Usage:
289310`-f "type:any` -> all pipelines
290311`-f "type:playback"` -> playback pipelines
291312`-f "type:capture & pga"` -> capture pipelines with PGA
292313`-f "pga & eq"` -> pipelines with both EQ and PGA
293314`-f "id:3"` -> pipeline whose id is 3
315+
316+ WARNING: usual boolean precedence does NOT apply! Filters are naively
317+ applied from left to right. For instance you could expect "id:2 | pga & id:1"
318+ to be interpreted as "id:2 | (pga & id:1)" and to return nothing.
319+ "id" cannot be both 1 and 2. But no: this script applies it from
320+ left to right like this: "(id:2 | pga) & id:1" so it is equivalent to
321+ "pga & id:1"
322+
294323''' )
295324 parser .add_argument ('-b' , '--block' , type = str ,
296325 help = 'setup block filter, command line parameter format is the same as -f argument' )
0 commit comments