mirror of
https://github.com/logos-storage/multicodec.git
synced 2026-01-02 05:23:07 +00:00
Previously, we called these foo-ns. Now we just call them foo (the fact that they're "namespaces" is implicit. This way, the path component always matches the multicodec name (for both multiaddr and other path types).
98 lines
3.4 KiB
Python
Executable File
98 lines
3.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
|
||
import csv
|
||
import sys
|
||
import re
|
||
|
||
def check(fname='table.csv'):
|
||
class CheckError(Exception):
|
||
pass
|
||
|
||
success = True
|
||
with open(fname) as table:
|
||
tablereader = csv.reader(table, strict=True, skipinitialspace=False)
|
||
codes = {}
|
||
names = {}
|
||
headerOffsets = []
|
||
lastCode = -1
|
||
for line, row in enumerate(tablereader):
|
||
try:
|
||
# Check the padding of each column
|
||
offset = 0
|
||
for col, item in enumerate(row):
|
||
le = len(item)
|
||
if col == 0: # first column 0 has no padding
|
||
offset = le
|
||
continue
|
||
offset = offset + le
|
||
thisOffset = offset - len(item.lstrip())
|
||
if line == 0: # header line sets the standard
|
||
headerOffsets.append(thisOffset)
|
||
elif col < len(headerOffsets) or le != 0:
|
||
if thisOffset != headerOffsets[col - 1]:
|
||
raise CheckError(f"bad spacing at column {col}")
|
||
|
||
# Skip the header
|
||
if line == 0:
|
||
continue
|
||
|
||
# Check for invalid rows
|
||
if len(row) != 5:
|
||
raise CheckError(f"expected 4 items, got {len(row)}")
|
||
|
||
[name, _, code, _, _] = row
|
||
|
||
# Check for a name
|
||
if not name:
|
||
raise CheckError(f"empty protocol name for code '{code}'")
|
||
|
||
# Check code format
|
||
if not re.match(r"^\s*0x([0-9a-f][0-9a-f])+$", code):
|
||
raise CheckError(f"code for '{name}' does not look like a byte sequence: '{code}'")
|
||
|
||
# Check name format
|
||
if not re.match(r"^[a-z][a-z0-9_-]+$", name):
|
||
raise CheckError(f"name '{name}' violates naming restrictions")
|
||
|
||
# Parse the code
|
||
try:
|
||
code = int(code, 16)
|
||
except Exception as e:
|
||
raise CheckError(f"failed to parse code '{code}' for '{name}': {e}")
|
||
|
||
# Check codes are ascending
|
||
ooo = code < lastCode
|
||
lastCode = code
|
||
if ooo:
|
||
raise CheckError(f"code {code} is out of order, previous code was {lastCode}")
|
||
|
||
# Finally, check for duplicates
|
||
|
||
if name in names:
|
||
raise CheckError(f"found duplicate {name}: {code} and {names[name]}")
|
||
else:
|
||
names[name] = code
|
||
|
||
if code in codes:
|
||
raise CheckError(
|
||
f"found duplicate for code {hex(code)} "
|
||
f"for '{codes[code]}' and '{name}'"
|
||
)
|
||
else:
|
||
codes[code] = name
|
||
|
||
# Reserved Code Range: Private Use Area – Do not permit any codes in this range
|
||
if code in range(0x300000, 0x400000):
|
||
raise CheckError(
|
||
f"found code in Private Use Area: {hex(code)} with name '{name}'"
|
||
)
|
||
except CheckError as e:
|
||
success = False
|
||
print(f"row {line}: {e}", file=sys.stderr)
|
||
|
||
return success
|
||
|
||
if __name__ == "__main__":
|
||
if not check():
|
||
sys.exit(1)
|