diff options
-rw-r--r-- | CONTRIBUTING.md | 6 | ||||
-rwxr-xr-x | bin/format-json.sh | 19 | ||||
-rw-r--r-- | etc/repos.in.json | 26 | ||||
-rw-r--r-- | etc/repos.json | 60 | ||||
-rw-r--r-- | format-json/EXPRESSIONS | 46 | ||||
-rw-r--r-- | format-json/RULES | 126 | ||||
-rw-r--r-- | format-json/TARGETS | 1 | ||||
-rw-r--r-- | format-json/TARGETS.tasks | 16 | ||||
-rw-r--r-- | format-json/generate-fmt.py | 24 |
9 files changed, 324 insertions, 0 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6badaf33..bb49ae60 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,6 +28,12 @@ is honored. As a consequence, (transitively) depending on the first time requires a significant amount of time to build the tools from first principles. This is also true when calling `bin/format-code.sh`. +Target, rules, and expression files should be formatted using +`bin/json-format.py`. The corresponding target is `["@", "format-json", "", ""]` +which provides a diff to be applied in order to obtain well-formatted +target, rules, and expression files; the script `bin/format-json.sh` +computes and applies that diff. + Changes should be organized as a patch series, i.e., as a sequence of small changes that are easy to review, but nevertheless self-contained in the sense that after each such change, the code builds and the diff --git a/bin/format-json.sh b/bin/format-json.sh new file mode 100755 index 00000000..6e1a4439 --- /dev/null +++ b/bin/format-json.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# Copyright 2025 Huawei Cloud Computing Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +: ${JUST_MR:=just-mr} + +cd $(readlink -f $(dirname $0)/..) +${JUST_MR} --main format-json build -p | (patch -p0) diff --git a/etc/repos.in.json b/etc/repos.in.json index aab0a492..6b98b384 100644 --- a/etc/repos.in.json +++ b/etc/repos.in.json @@ -497,6 +497,32 @@ , "lzma": "lzma" } } + , "repo": + {"repository": {"type": "file", "path": ".", "pragma": {"to_git": true}}} + , "format-json infra": + { "repository": + {"type": "file", "path": "format-json", "pragma": {"to_git": true}} + } + , "repo tree": + { "repository": {"type": "tree structure", "repo": "repo"} + , "target_file_name": "TARGETS.tasks" + , "target_root": "format-json infra" + , "bindings": {"format": "format-json infra"} + } + , "format-json/tasks": + { "repository": + {"type": "computed", "repo": "repo tree", "target": ["", ""]} + } + , "format-json/bin": + { "repository": {"type": "file", "path": "bin", "pragma": {"to_git": true}} + , "target_root": "format-json infra" + } + , "format-json": + { "repository": {"type": "file", "path": "."} + , "target_root": "format-json/tasks" + , "rule_root": "format-json infra" + , "bindings": {"bin": "format-json/bin"} + } } , "imports": [ { "source": "git" diff --git a/etc/repos.json b/etc/repos.json index d444c262..fdc5e57f 100644 --- a/etc/repos.json +++ b/etc/repos.json @@ -657,6 +657,66 @@ "lzma": "lzma" } }, + "repo": { + "repository": { + "type": "file", + "path": ".", + "pragma": { + "to_git": true + } + } + }, + "format-json infra": { + "repository": { + "type": "file", + "path": "format-json", + "pragma": { + "to_git": true + } + } + }, + "repo tree": { + "repository": { + "type": "tree structure", + "repo": "repo" + }, + "target_file_name": "TARGETS.tasks", + "target_root": "format-json infra", + "bindings": { + "format": "format-json infra" + } + }, + "format-json/tasks": { + "repository": { + "type": "computed", + "repo": "repo tree", + "target": [ + "", + "" + ] + } + }, + "format-json/bin": { + "repository": { + "type": "file", + "path": "bin", + "pragma": { + "to_git": true + } + }, + "target_root": "format-json infra" + }, + "format-json": { + "repository": { + "type": "file", + "path": "." + }, + "target_root": "format-json/tasks", + "rule_root": "format-json infra", + "bindings": { + "bin": "format-json/bin" + } + }, "clang-18": { "repository": "clang-18/toolchains", "target_file_name": "clang.TARGETS", diff --git a/format-json/EXPRESSIONS b/format-json/EXPRESSIONS new file mode 100644 index 00000000..f1ca6f4a --- /dev/null +++ b/format-json/EXPRESSIONS @@ -0,0 +1,46 @@ +{ "stage_singleton_field": + { "vars": ["fieldname", "transition", "location"] + , "expression": + { "type": "assert_non_empty" + , "msg": + ["No artifact specified in field", {"type": "var", "name": "fieldname"}] + , "$1": + { "type": "disjoint_map_union" + , "msg": + [ "Expecting (essentially) a single artifact in field" + , {"type": "var", "name": "fieldname"} + ] + , "$1": + { "type": "foreach" + , "var": "src" + , "range": + {"type": "FIELD", "name": {"type": "var", "name": "fieldname"}} + , "body": + { "type": "disjoint_map_union" + , "$1": + { "type": "foreach" + , "var": "artifact" + , "range": + { "type": "values" + , "$1": + { "type": "DEP_ARTIFACTS" + , "dep": {"type": "var", "name": "src"} + , "transition": + { "type": "var" + , "name": "transition" + , "default": {"type": "empty_map"} + } + } + } + , "body": + { "type": "singleton_map" + , "key": {"type": "var", "name": "location"} + , "value": {"type": "var", "name": "artifact"} + } + } + } + } + } + } + } +} diff --git a/format-json/RULES b/format-json/RULES new file mode 100644 index 00000000..1bfb36cb --- /dev/null +++ b/format-json/RULES @@ -0,0 +1,126 @@ +{ "fmt": + { "target_fields": ["files"] + , "implicit": {"formatter": [["@", "bin", "", "json-format.py"]]} + , "imports": {"stage": "stage_singleton_field"} + , "tainted": ["lint"] + , "expression": + { "type": "let*" + , "bindings": + [ ["fieldname", "formatter"] + , ["location", "format"] + , ["format", {"type": "CALL_EXPRESSION", "name": "stage"}] + , [ "diffs" + , { "type": "disjoint_map_union" + , "$1": + { "type": "foreach" + , "var": "dep" + , "range": {"type": "FIELD", "name": "files"} + , "body": + { "type": "disjoint_map_union" + , "$1": + { "type": "foreach_map" + , "range": + { "type": "DEP_ARTIFACTS" + , "dep": {"type": "var", "name": "dep"} + } + , "body": + { "type": "ACTION" + , "outs": + [ { "type": "join" + , "$1": [{"type": "var", "name": "_"}, ".diff"] + } + ] + , "inputs": + { "type": "disjoint_map_union" + , "$1": + [ {"type": "var", "name": "format"} + , { "type": "singleton_map" + , "key": + { "type": "join" + , "$1": [{"type": "var", "name": "_"}, ".orig"] + } + , "value": {"type": "var", "name": "$_"} + } + ] + } + , "cmd": + [ "sh" + , "-c" + , { "type": "join" + , "separator": " " + , "$1": + [ "./format -s" + , { "type": "join_cmd" + , "$1": + [ { "type": "join" + , "$1": [{"type": "var", "name": "_"}, ".orig"] + } + ] + } + , ">" + , { "type": "join_cmd" + , "$1": [{"type": "var", "name": "_"}] + } + , "&& diff -u" + , { "type": "join_cmd" + , "$1": + [ { "type": "join" + , "$1": [{"type": "var", "name": "_"}, ".orig"] + } + ] + } + , { "type": "join_cmd" + , "$1": [{"type": "var", "name": "_"}] + } + , ">" + , { "type": "join_cmd" + , "$1": + [ { "type": "join" + , "$1": [{"type": "var", "name": "_"}, ".diff"] + } + ] + } + ] + } + ] + , "may_fail": ["lint"] + , "fail_message": + { "type": "join" + , "$1": + [ "Target file " + , {"type": "var", "name": "_"} + , " not formatted correctly." + ] + } + } + } + } + } + } + ] + , [ "diff" + , { "type": "ACTION" + , "inputs": {"type": "var", "name": "diffs"} + , "outs": ["targets.diff"] + , "cmd": + [ "sh" + , "-c" + , { "type": "join" + , "separator": " " + , "$1": + [ "cat" + , { "type": "join_cmd" + , "$1": + {"type": "keys", "$1": {"type": "var", "name": "diffs"}} + } + , "> targets.diff" + ] + } + ] + } + ] + ] + , "body": {"type": "RESULT", "artifacts": {"type": "var", "name": "diff"}} + } + } +} diff --git a/format-json/TARGETS b/format-json/TARGETS new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/format-json/TARGETS @@ -0,0 +1 @@ +{} diff --git a/format-json/TARGETS.tasks b/format-json/TARGETS.tasks new file mode 100644 index 00000000..2eb54fb8 --- /dev/null +++ b/format-json/TARGETS.tasks @@ -0,0 +1,16 @@ +{ "ls": + { "type": "generic" + , "outs": ["json-files"] + , "cmds": + [ "find . '(' -name 'TARGETS*' -o -name RULES -o -name EXPRESSIONS ')' -type f > json-files" + ] + , "deps": [["TREE", null, "."]] + } +, "targets": + { "type": "generic" + , "outs": ["TARGETS"] + , "cmds": ["python3 generate-fmt.py"] + , "deps": ["ls", ["@", "format", "", "generate-fmt.py"]] + } +, "": {"type": "export", "target": "targets"} +} diff --git a/format-json/generate-fmt.py b/format-json/generate-fmt.py new file mode 100644 index 00000000..de2c5391 --- /dev/null +++ b/format-json/generate-fmt.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# Copyright 2025 Huawei Cloud Computing Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json + +with open("json-files") as f: + tfiles = f.read().splitlines() + +targets = {"": {"type": "fmt", "files": [t.removeprefix("./") for t in tfiles]}} + +with open("TARGETS", "w") as f: + json.dump(targets, f, indent=2) |