Introduce repeatable_string_flag. (#593)

New settings of this flag type do not override each other; they are concatenated into a list. --foo=bar --foo=baz -> [bar, baz]. This is the equivalent of a string typed native flag with allow_multiple.

Pull out scope attr into a variable.
diff --git a/docs/common_settings_doc.md b/docs/common_settings_doc.md
index 346b75c..318b09a 100755
--- a/docs/common_settings_doc.md
+++ b/docs/common_settings_doc.md
@@ -94,6 +94,27 @@
 | <a id="int_setting-scope"></a>scope |  The scope indicates where a flag can propagate to   | String | optional |  `"universal"`  |
 
 
+<a id="repeatable_string_flag"></a>
+
+## repeatable_string_flag
+
+<pre>
+load("@bazel_skylib//rules:common_settings.bzl", "repeatable_string_flag")
+
+repeatable_string_flag(<a href="#repeatable_string_flag-name">name</a>, <a href="#repeatable_string_flag-scope">scope</a>)
+</pre>
+
+A build setting that accepts one or more string-typed settings on the command line, with the values concatenated into a single string list; for example, `--//my/setting=foo` `--//my/setting=bar` will be parsed as `['foo', 'bar']`. Contrast with `string_list_flag`
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="repeatable_string_flag-name"></a>name |  A unique name for this target.   | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required |  |
+| <a id="repeatable_string_flag-scope"></a>scope |  The scope indicates where a flag can propagate to   | String | optional |  `"universal"`  |
+
+
 <a id="string_flag"></a>
 
 ## string_flag
@@ -148,7 +169,7 @@
 string_list_setting(<a href="#string_list_setting-name">name</a>, <a href="#string_list_setting-scope">scope</a>)
 </pre>
 
-A string list-typed build setting that cannot be set on the command line
+A string list-typed build setting which expects its value on the command line to be given in comma-separated format; for example, `--//my/setting=foo,bar` will be parsed as `['foo', 'bar']`. Contrast with `repeatable_string_flag`
 
 **ATTRIBUTES**
 
diff --git a/rules/common_settings.bzl b/rules/common_settings.bzl
index aba40c2..4e9bcaa 100644
--- a/rules/common_settings.bzl
+++ b/rules/common_settings.bzl
@@ -36,6 +36,11 @@
           "attribute.",
 )
 
+_SCOPE_ATTR = attr.string(
+    doc = "The scope indicates where a flag can propagate to",
+    default = "universal",
+)
+
 def _is_valid_make_variable_char(c):
     # Restrict make variable names for consistency with predefined ones. There are no enforced
     # restrictions on make variable names, but when they contain e.g. spaces or braces, they
@@ -66,10 +71,7 @@
     build_setting = config.int(flag = True),
     attrs = {
         "make_variable": _MAKE_VARIABLE_ATTR,
-        "scope": attr.string(
-            doc = "The scope indicates where a flag can propagate to",
-            default = "universal",
-        ),
+        "scope": _SCOPE_ATTR,
     },
     doc = "An int-typed build setting that can be set on the command line",
 )
@@ -79,10 +81,7 @@
     build_setting = config.int(),
     attrs = {
         "make_variable": _MAKE_VARIABLE_ATTR,
-        "scope": attr.string(
-            doc = "The scope indicates where a flag can propagate to",
-            default = "universal",
-        ),
+        "scope": _SCOPE_ATTR,
     },
     doc = "An int-typed build setting that cannot be set on the command line",
 )
@@ -91,10 +90,7 @@
     implementation = _impl,
     build_setting = config.bool(flag = True),
     attrs = {
-        "scope": attr.string(
-            doc = "The scope indicates where a flag can propagate to",
-            default = "universal",
-        ),
+        "scope": _SCOPE_ATTR,
     },
     doc = "A bool-typed build setting that can be set on the command line",
 )
@@ -103,10 +99,7 @@
     implementation = _impl,
     build_setting = config.bool(),
     attrs = {
-        "scope": attr.string(
-            doc = "The scope indicates where a flag can propagate to",
-            default = "universal",
-        ),
+        "scope": _SCOPE_ATTR,
     },
     doc = "A bool-typed build setting that cannot be set on the command line",
 )
@@ -115,24 +108,33 @@
     implementation = _impl,
     build_setting = config.string_list(flag = True),
     attrs = {
-        "scope": attr.string(
-            doc = "The scope indicates where a flag can propagate to",
-            default = "universal",
-        ),
+        "scope": _SCOPE_ATTR,
     },
     doc = "A string list-typed build setting that can be set on the command line",
 )
 
+def _repeatable_string_flag_impl(ctx):
+    return BuildSettingInfo(value = ctx.build_setting_value)
+
+repeatable_string_flag = rule(
+    implementation = _repeatable_string_flag_impl,
+    build_setting = config.string_list(
+        flag = True,
+        repeatable = True,
+    ),
+    attrs = {
+        "scope": _SCOPE_ATTR,
+    },
+    doc = "A build setting that accepts one or more string-typed settings on the command line, with the values concatenated into a single string list; for example, `--//my/setting=foo` `--//my/setting=bar` will be parsed as `['foo', 'bar']`. Contrast with `string_list_flag`",
+)
+
 string_list_setting = rule(
     implementation = _impl,
     build_setting = config.string_list(),
     attrs = {
-        "scope": attr.string(
-            doc = "The scope indicates where a flag can propagate to",
-            default = "universal",
-        ),
+        "scope": _SCOPE_ATTR,
     },
-    doc = "A string list-typed build setting that cannot be set on the command line",
+    doc = "A string list-typed build setting which expects its value on the command line to be given in comma-separated format; for example, `--//my/setting=foo,bar` will be parsed as `['foo', 'bar']`. Contrast with `repeatable_string_flag`",
 )
 
 def _no_at_str(label):
@@ -160,10 +162,7 @@
             doc = "The list of allowed values for this setting. An error is raised if any other value is given.",
         ),
         "make_variable": _MAKE_VARIABLE_ATTR,
-        "scope": attr.string(
-            doc = "The scope indicates where a flag can propagate to",
-            default = "universal",
-        ),
+        "scope": _SCOPE_ATTR,
     },
     doc = "A string-typed build setting that can be set on the command line",
 )
@@ -176,10 +175,7 @@
             doc = "The list of allowed values for this setting. An error is raised if any other value is given.",
         ),
         "make_variable": _MAKE_VARIABLE_ATTR,
-        "scope": attr.string(
-            doc = "The scope indicates where a flag can propagate to",
-            default = "universal",
-        ),
+        "scope": _SCOPE_ATTR,
     },
     doc = "A string-typed build setting that cannot be set on the command line",
 )