summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md6
-rwxr-xr-xbin/format-json.sh19
-rw-r--r--etc/repos.in.json26
-rw-r--r--etc/repos.json60
-rw-r--r--format-json/EXPRESSIONS46
-rw-r--r--format-json/RULES126
-rw-r--r--format-json/TARGETS1
-rw-r--r--format-json/TARGETS.tasks16
-rw-r--r--format-json/generate-fmt.py24
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)