mirror of https://github.com/k3s-io/k3s
Merge pull request #74904 from sttts/sttts-proto-tests
Rework proto generation scripts and add testspull/564/head
commit
f8024ab087
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"ImportPath": "k8s.io/kubernetes",
|
"ImportPath": "k8s.io/kubernetes",
|
||||||
"GoVersion": "go1.11",
|
"GoVersion": "go1.12",
|
||||||
"GodepVersion": "v80-k8s-r1",
|
"GodepVersion": "v80-k8s-r1",
|
||||||
"Packages": [
|
"Packages": [
|
||||||
"github.com/bazelbuild/bazel-gazelle/cmd/gazelle",
|
"github.com/bazelbuild/bazel-gazelle/cmd/gazelle",
|
||||||
|
@ -3884,6 +3884,10 @@
|
||||||
"ImportPath": "gonum.org/v1/gonum/graph/formats/dot/internal/token",
|
"ImportPath": "gonum.org/v1/gonum/graph/formats/dot/internal/token",
|
||||||
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/graph/internal/linear",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gonum.org/v1/gonum/graph/internal/ordered",
|
"ImportPath": "gonum.org/v1/gonum/graph/internal/ordered",
|
||||||
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
@ -3900,6 +3904,14 @@
|
||||||
"ImportPath": "gonum.org/v1/gonum/graph/simple",
|
"ImportPath": "gonum.org/v1/gonum/graph/simple",
|
||||||
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/graph/topo",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/graph/traverse",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gonum.org/v1/gonum/internal/asm/c128",
|
"ImportPath": "gonum.org/v1/gonum/internal/asm/c128",
|
||||||
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
|
|
@ -103221,6 +103221,36 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
= vendor/gonum.org/v1/gonum/graph/internal/linear licensed under: =
|
||||||
|
|
||||||
|
Copyright ©2013 The Gonum Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the gonum project nor the names of its authors and
|
||||||
|
contributors may be used to endorse or promote products derived from this
|
||||||
|
software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
= vendor/gonum.org/v1/gonum/LICENSE 665e67d07d85e236cceb8de602c6255a
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
= vendor/gonum.org/v1/gonum/graph/internal/ordered licensed under: =
|
= vendor/gonum.org/v1/gonum/graph/internal/ordered licensed under: =
|
||||||
|
|
||||||
|
@ -103341,6 +103371,66 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
= vendor/gonum.org/v1/gonum/graph/topo licensed under: =
|
||||||
|
|
||||||
|
Copyright ©2013 The Gonum Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the gonum project nor the names of its authors and
|
||||||
|
contributors may be used to endorse or promote products derived from this
|
||||||
|
software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
= vendor/gonum.org/v1/gonum/LICENSE 665e67d07d85e236cceb8de602c6255a
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
= vendor/gonum.org/v1/gonum/graph/traverse licensed under: =
|
||||||
|
|
||||||
|
Copyright ©2013 The Gonum Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the gonum project nor the names of its authors and
|
||||||
|
contributors may be used to endorse or promote products derived from this
|
||||||
|
software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
= vendor/gonum.org/v1/gonum/LICENSE 665e67d07d85e236cceb8de602c6255a
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
= vendor/gonum.org/v1/gonum/internal/asm/c128 licensed under: =
|
= vendor/gonum.org/v1/gonum/internal/asm/c128 licensed under: =
|
||||||
|
|
||||||
|
|
|
@ -41,57 +41,8 @@ fi
|
||||||
|
|
||||||
gotoprotobuf=$(kube::util::find-binary "go-to-protobuf")
|
gotoprotobuf=$(kube::util::find-binary "go-to-protobuf")
|
||||||
|
|
||||||
PACKAGES=(
|
APIROOTS=( ${1} )
|
||||||
k8s.io/apiserver/pkg/apis/example/v1
|
shift
|
||||||
k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1
|
|
||||||
k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1
|
|
||||||
k8s.io/kube-aggregator/pkg/apis/apiregistration/v1
|
|
||||||
k8s.io/api/core/v1
|
|
||||||
k8s.io/api/policy/v1beta1
|
|
||||||
k8s.io/api/extensions/v1beta1
|
|
||||||
k8s.io/api/autoscaling/v1
|
|
||||||
k8s.io/api/authorization/v1
|
|
||||||
k8s.io/api/autoscaling/v2beta1
|
|
||||||
k8s.io/api/autoscaling/v2beta2
|
|
||||||
k8s.io/api/authorization/v1beta1
|
|
||||||
k8s.io/api/batch/v1
|
|
||||||
k8s.io/api/batch/v1beta1
|
|
||||||
k8s.io/api/batch/v2alpha1
|
|
||||||
k8s.io/api/apps/v1beta1
|
|
||||||
k8s.io/api/apps/v1beta2
|
|
||||||
k8s.io/api/apps/v1
|
|
||||||
k8s.io/api/authentication/v1
|
|
||||||
k8s.io/api/authentication/v1beta1
|
|
||||||
k8s.io/api/events/v1beta1
|
|
||||||
k8s.io/api/rbac/v1alpha1
|
|
||||||
k8s.io/api/rbac/v1beta1
|
|
||||||
k8s.io/api/rbac/v1
|
|
||||||
k8s.io/api/certificates/v1beta1
|
|
||||||
k8s.io/api/coordination/v1beta1
|
|
||||||
k8s.io/api/coordination/v1
|
|
||||||
k8s.io/api/imagepolicy/v1alpha1
|
|
||||||
k8s.io/api/scheduling/v1alpha1
|
|
||||||
k8s.io/api/scheduling/v1beta1
|
|
||||||
k8s.io/api/scheduling/v1
|
|
||||||
k8s.io/api/settings/v1alpha1
|
|
||||||
k8s.io/api/storage/v1alpha1
|
|
||||||
k8s.io/api/storage/v1beta1
|
|
||||||
k8s.io/api/storage/v1
|
|
||||||
k8s.io/api/admissionregistration/v1beta1
|
|
||||||
k8s.io/api/admission/v1beta1
|
|
||||||
k8s.io/api/auditregistration/v1alpha1
|
|
||||||
k8s.io/api/networking/v1beta1
|
|
||||||
k8s.io/api/networking/v1
|
|
||||||
k8s.io/metrics/pkg/apis/metrics/v1alpha1
|
|
||||||
k8s.io/metrics/pkg/apis/metrics/v1beta1
|
|
||||||
k8s.io/metrics/pkg/apis/custom_metrics/v1beta1
|
|
||||||
k8s.io/metrics/pkg/apis/custom_metrics/v1beta2
|
|
||||||
k8s.io/metrics/pkg/apis/external_metrics/v1beta1
|
|
||||||
k8s.io/apiserver/pkg/apis/audit/v1alpha1
|
|
||||||
k8s.io/apiserver/pkg/apis/audit/v1beta1
|
|
||||||
k8s.io/apiserver/pkg/apis/audit/v1
|
|
||||||
k8s.io/apiserver/pkg/apis/example2/v1
|
|
||||||
)
|
|
||||||
|
|
||||||
# requires the 'proto' tag to build (will remove when ready)
|
# requires the 'proto' tag to build (will remove when ready)
|
||||||
# searches for the protoc-gen-gogo extension in the output directory
|
# searches for the protoc-gen-gogo extension in the output directory
|
||||||
|
@ -101,6 +52,6 @@ PATH="${KUBE_ROOT}/_output/bin:${PATH}" \
|
||||||
"${gotoprotobuf}" \
|
"${gotoprotobuf}" \
|
||||||
--proto-import="${KUBE_ROOT}/vendor" \
|
--proto-import="${KUBE_ROOT}/vendor" \
|
||||||
--proto-import="${KUBE_ROOT}/third_party/protobuf" \
|
--proto-import="${KUBE_ROOT}/third_party/protobuf" \
|
||||||
--packages=$(IFS=, ; echo "${PACKAGES[*]}") \
|
--packages=$(IFS=, ; echo "${APIROOTS[*]}") \
|
||||||
--go-header-file ${KUBE_ROOT}/hack/boilerplate/boilerplate.generatego.txt \
|
--go-header-file ${KUBE_ROOT}/hack/boilerplate/boilerplate.generatego.txt \
|
||||||
"$@"
|
"$@"
|
||||||
|
|
|
@ -24,6 +24,12 @@ KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
|
||||||
# source tree. This is managed in kube::build::copy_output in build/common.sh.
|
# source tree. This is managed in kube::build::copy_output in build/common.sh.
|
||||||
# If the output set is changed update that function.
|
# If the output set is changed update that function.
|
||||||
|
|
||||||
"${KUBE_ROOT}/build/run.sh" hack/update-generated-protobuf-dockerized.sh "$@"
|
APIROOTS=${APIROOTS:-$(git grep --files-with-matches -e '// +k8s:protobuf-gen=package' cmd pkg staging | \
|
||||||
|
xargs -n 1 dirname | \
|
||||||
|
sed 's,^,k8s.io/kubernetes/,;s,k8s.io/kubernetes/staging/src/,,' | \
|
||||||
|
sort | uniq
|
||||||
|
)}
|
||||||
|
|
||||||
|
"${KUBE_ROOT}/build/run.sh" hack/update-generated-protobuf-dockerized.sh "${APIROOTS}" "$@"
|
||||||
|
|
||||||
# ex: ts=2 sw=2 et filetype=sh
|
# ex: ts=2 sw=2 et filetype=sh
|
||||||
|
|
|
@ -23,7 +23,8 @@ source "${KUBE_ROOT}/hack/lib/init.sh"
|
||||||
|
|
||||||
kube::golang::setup_env
|
kube::golang::setup_env
|
||||||
|
|
||||||
APIROOTS=${APIROOTS:-pkg/api pkg/apis pkg/watch staging/src/k8s.io/apimachinery/pkg/api staging/src/k8s.io/apimachinery/pkg/apis staging/src/k8s.io/apiserver/pkg staging/src/k8s.io/api staging/src/k8s.io/metrics/pkg/apis}
|
APIROOTS=$(git grep --files-with-matches -e '// +k8s:protobuf-gen=package' cmd pkg staging | xargs -n 1 dirname | sort | uniq)
|
||||||
|
|
||||||
_tmp="${KUBE_ROOT}/_tmp"
|
_tmp="${KUBE_ROOT}/_tmp"
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=false
|
// +k8s:openapi-gen=false
|
||||||
|
|
||||||
// +groupName=admission.k8s.io
|
// +groupName=admission.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
// +groupName=admissionregistration.k8s.io
|
// +groupName=admissionregistration.k8s.io
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
package v1 // import "k8s.io/api/apps/v1"
|
package v1 // import "k8s.io/api/apps/v1"
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
package v1beta1 // import "k8s.io/api/apps/v1beta1"
|
package v1beta1 // import "k8s.io/api/apps/v1beta1"
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
package v1beta2 // import "k8s.io/api/apps/v1beta2"
|
package v1beta2 // import "k8s.io/api/apps/v1beta2"
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
// +groupName=auditregistration.k8s.io
|
// +groupName=auditregistration.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +groupName=authentication.k8s.io
|
// +groupName=authentication.k8s.io
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +groupName=authentication.k8s.io
|
// +groupName=authentication.k8s.io
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
// +groupName=authorization.k8s.io
|
// +groupName=authorization.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
// +groupName=authorization.k8s.io
|
// +groupName=authorization.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
package v1 // import "k8s.io/api/autoscaling/v1"
|
package v1 // import "k8s.io/api/autoscaling/v1"
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
package v2beta1 // import "k8s.io/api/autoscaling/v2beta1"
|
package v2beta1 // import "k8s.io/api/autoscaling/v2beta1"
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
package v2beta2 // import "k8s.io/api/autoscaling/v2beta2"
|
package v2beta2 // import "k8s.io/api/autoscaling/v2beta2"
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
package v1 // import "k8s.io/api/batch/v1"
|
package v1 // import "k8s.io/api/batch/v1"
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
package v1beta1 // import "k8s.io/api/batch/v1beta1"
|
package v1beta1 // import "k8s.io/api/batch/v1beta1"
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
package v2alpha1 // import "k8s.io/api/batch/v2alpha1"
|
package v2alpha1 // import "k8s.io/api/batch/v2alpha1"
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
// +groupName=certificates.k8s.io
|
// +groupName=certificates.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
// +groupName=coordination.k8s.io
|
// +groupName=coordination.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
// +groupName=coordination.k8s.io
|
// +groupName=coordination.k8s.io
|
||||||
|
|
|
@ -16,6 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
|
|
||||||
// Package v1 is the v1 version of the core API.
|
// Package v1 is the v1 version of the core API.
|
||||||
package v1 // import "k8s.io/api/core/v1"
|
package v1 // import "k8s.io/api/core/v1"
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
// +groupName=events.k8s.io
|
// +groupName=events.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
package v1beta1 // import "k8s.io/api/extensions/v1beta1"
|
package v1beta1 // import "k8s.io/api/extensions/v1beta1"
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
// +groupName=imagepolicy.k8s.io
|
// +groupName=imagepolicy.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
// +groupName=networking.k8s.io
|
// +groupName=networking.k8s.io
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
// +groupName=networking.k8s.io
|
// +groupName=networking.k8s.io
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
// Package policy is for any kind of policy object. Suitable examples, even if
|
// Package policy is for any kind of policy object. Suitable examples, even if
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
// +groupName=rbac.authorization.k8s.io
|
// +groupName=rbac.authorization.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
// +groupName=rbac.authorization.k8s.io
|
// +groupName=rbac.authorization.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
// +groupName=rbac.authorization.k8s.io
|
// +groupName=rbac.authorization.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
// +groupName=scheduling.k8s.io
|
// +groupName=scheduling.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
// +groupName=scheduling.k8s.io
|
// +groupName=scheduling.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
// +groupName=scheduling.k8s.io
|
// +groupName=scheduling.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
// +groupName=settings.k8s.io
|
// +groupName=settings.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +groupName=storage.k8s.io
|
// +groupName=storage.k8s.io
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,8 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package,register
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +groupName=storage.k8s.io
|
// +groupName=storage.k8s.io
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +groupName=storage.k8s.io
|
// +groupName=storage.k8s.io
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:conversion-gen=k8s.io/apiextensions-apiserver/pkg/apis/apiextensions
|
// +k8s:conversion-gen=k8s.io/apiextensions-apiserver/pkg/apis/apiextensions
|
||||||
// +k8s:defaulter-gen=TypeMeta
|
// +k8s:defaulter-gen=TypeMeta
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/audit
|
// +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/audit
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
// +k8s:defaulter-gen=TypeMeta
|
// +k8s:defaulter-gen=TypeMeta
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/audit
|
// +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/audit
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
// +k8s:defaulter-gen=TypeMeta
|
// +k8s:defaulter-gen=TypeMeta
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/audit
|
// +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/audit
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
// +k8s:defaulter-gen=TypeMeta
|
// +k8s:defaulter-gen=TypeMeta
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/example
|
// +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/example
|
||||||
// +k8s:openapi-gen=false
|
// +k8s:openapi-gen=false
|
||||||
// +k8s:defaulter-gen=TypeMeta
|
// +k8s:defaulter-gen=TypeMeta
|
||||||
|
|
|
@ -154,6 +154,86 @@
|
||||||
"ImportPath": "golang.org/x/tools/internal/semver",
|
"ImportPath": "golang.org/x/tools/internal/semver",
|
||||||
"Rev": "7f7074d5bcfd282eb16bc382b0bb3da762461985"
|
"Rev": "7f7074d5bcfd282eb16bc382b0bb3da762461985"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/blas",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/blas/blas64",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/blas/gonum",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/floats",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/graph",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/graph/internal/linear",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/graph/internal/ordered",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/graph/internal/set",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/graph/internal/uid",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/graph/simple",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/graph/topo",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/graph/traverse",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/internal/asm/c128",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/internal/asm/f32",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/internal/asm/f64",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/internal/math32",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/lapack",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/lapack/gonum",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/lapack/lapack64",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gonum.org/v1/gonum/mat",
|
||||||
|
"Rev": "cebdade430ccb61c1feba4878085f6cf8cb3320e"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "k8s.io/gengo/args",
|
"ImportPath": "k8s.io/gengo/args",
|
||||||
"Rev": "51747d6e00da1fc578d5a333a93bb2abcbce7a95"
|
"Rev": "51747d6e00da1fc578d5a333a93bb2abcbce7a95"
|
||||||
|
|
|
@ -23,6 +23,9 @@ go_library(
|
||||||
"//staging/src/k8s.io/code-generator/pkg/util:go_default_library",
|
"//staging/src/k8s.io/code-generator/pkg/util:go_default_library",
|
||||||
"//staging/src/k8s.io/code-generator/third_party/forked/golang/reflect:go_default_library",
|
"//staging/src/k8s.io/code-generator/third_party/forked/golang/reflect:go_default_library",
|
||||||
"//vendor/github.com/spf13/pflag:go_default_library",
|
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||||
|
"//vendor/gonum.org/v1/gonum/graph:go_default_library",
|
||||||
|
"//vendor/gonum.org/v1/gonum/graph/simple:go_default_library",
|
||||||
|
"//vendor/gonum.org/v1/gonum/graph/topo:go_default_library",
|
||||||
"//vendor/k8s.io/gengo/args:go_default_library",
|
"//vendor/k8s.io/gengo/args:go_default_library",
|
||||||
"//vendor/k8s.io/gengo/generator:go_default_library",
|
"//vendor/k8s.io/gengo/generator:go_default_library",
|
||||||
"//vendor/k8s.io/gengo/namer:go_default_library",
|
"//vendor/k8s.io/gengo/namer:go_default_library",
|
||||||
|
|
|
@ -25,16 +25,20 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
flag "github.com/spf13/pflag"
|
||||||
|
"gonum.org/v1/gonum/graph"
|
||||||
|
"gonum.org/v1/gonum/graph/simple"
|
||||||
|
"gonum.org/v1/gonum/graph/topo"
|
||||||
|
|
||||||
"k8s.io/code-generator/pkg/util"
|
"k8s.io/code-generator/pkg/util"
|
||||||
"k8s.io/gengo/args"
|
"k8s.io/gengo/args"
|
||||||
"k8s.io/gengo/generator"
|
"k8s.io/gengo/generator"
|
||||||
"k8s.io/gengo/namer"
|
"k8s.io/gengo/namer"
|
||||||
"k8s.io/gengo/parser"
|
"k8s.io/gengo/parser"
|
||||||
"k8s.io/gengo/types"
|
"k8s.io/gengo/types"
|
||||||
|
|
||||||
flag "github.com/spf13/pflag"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Generator struct {
|
type Generator struct {
|
||||||
|
@ -202,6 +206,18 @@ func Run(g *Generator) {
|
||||||
c.Verify = g.Common.VerifyOnly
|
c.Verify = g.Common.VerifyOnly
|
||||||
c.FileTypes["protoidl"] = NewProtoFile()
|
c.FileTypes["protoidl"] = NewProtoFile()
|
||||||
|
|
||||||
|
// order package by imports, importees first
|
||||||
|
deps := deps(c, protobufNames.packages)
|
||||||
|
order, err := importOrder(deps)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to order packages by imports: %v", err)
|
||||||
|
}
|
||||||
|
topologicalPos := map[string]int{}
|
||||||
|
for i, p := range order {
|
||||||
|
topologicalPos[p] = i
|
||||||
|
}
|
||||||
|
sort.Sort(positionOrder{topologicalPos, protobufNames.packages})
|
||||||
|
|
||||||
var vendoredOutputPackages, localOutputPackages generator.Packages
|
var vendoredOutputPackages, localOutputPackages generator.Packages
|
||||||
for _, p := range protobufNames.packages {
|
for _, p := range protobufNames.packages {
|
||||||
if _, ok := nonOutputPackages[p.Name()]; ok {
|
if _, ok := nonOutputPackages[p.Name()]; ok {
|
||||||
|
@ -347,3 +363,66 @@ func Run(g *Generator) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deps(c *generator.Context, pkgs []*protobufPackage) map[string][]string {
|
||||||
|
ret := map[string][]string{}
|
||||||
|
for _, p := range pkgs {
|
||||||
|
for _, d := range c.Universe[p.PackagePath].Imports {
|
||||||
|
ret[p.PackagePath] = append(ret[p.PackagePath], d.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func importOrder(deps map[string][]string) ([]string, error) {
|
||||||
|
nodes := map[string]graph.Node{}
|
||||||
|
names := map[int64]string{}
|
||||||
|
g := simple.NewDirectedGraph()
|
||||||
|
for pkg, imports := range deps {
|
||||||
|
for _, imp := range imports {
|
||||||
|
if _, found := nodes[pkg]; !found {
|
||||||
|
n := g.NewNode()
|
||||||
|
g.AddNode(n)
|
||||||
|
nodes[pkg] = n
|
||||||
|
names[n.ID()] = pkg
|
||||||
|
}
|
||||||
|
if _, found := nodes[imp]; !found {
|
||||||
|
n := g.NewNode()
|
||||||
|
g.AddNode(n)
|
||||||
|
nodes[imp] = n
|
||||||
|
names[n.ID()] = imp
|
||||||
|
}
|
||||||
|
g.SetEdge(g.NewEdge(nodes[imp], nodes[pkg]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := []string{}
|
||||||
|
sorted, err := topo.Sort(g)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, n := range sorted {
|
||||||
|
ret = append(ret, names[n.ID()])
|
||||||
|
fmt.Println("topological order", names[n.ID()])
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type positionOrder struct {
|
||||||
|
pos map[string]int
|
||||||
|
elements []*protobufPackage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o positionOrder) Len() int {
|
||||||
|
return len(o.elements)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o positionOrder) Less(i, j int) bool {
|
||||||
|
return o.pos[o.elements[i].PackagePath] < o.pos[o.elements[j].PackagePath]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o positionOrder) Swap(i, j int) {
|
||||||
|
x := o.elements[i]
|
||||||
|
o.elements[i] = o.elements[j]
|
||||||
|
o.elements[j] = x
|
||||||
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package,register
|
// +k8s:deepcopy-gen=package
|
||||||
// +groupName=csi.storage.k8s.io
|
// +groupName=csi.storage.k8s.io
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:conversion-gen=k8s.io/kube-aggregator/pkg/apis/apiregistration
|
// +k8s:conversion-gen=k8s.io/kube-aggregator/pkg/apis/apiregistration
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
// +groupName=apiregistration.k8s.io
|
// +groupName=apiregistration.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:conversion-gen=k8s.io/kube-aggregator/pkg/apis/apiregistration
|
// +k8s:conversion-gen=k8s.io/kube-aggregator/pkg/apis/apiregistration
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
// +groupName=apiregistration.k8s.io
|
// +groupName=apiregistration.k8s.io
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:conversion-gen=k8s.io/metrics/pkg/apis/custom_metrics
|
// +k8s:conversion-gen=k8s.io/metrics/pkg/apis/custom_metrics
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:conversion-gen=k8s.io/metrics/pkg/apis/custom_metrics
|
// +k8s:conversion-gen=k8s.io/metrics/pkg/apis/custom_metrics
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:conversion-gen=k8s.io/metrics/pkg/apis/external_metrics
|
// +k8s:conversion-gen=k8s.io/metrics/pkg/apis/external_metrics
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:conversion-gen=k8s.io/metrics/pkg/apis/metrics
|
// +k8s:conversion-gen=k8s.io/metrics/pkg/apis/metrics
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=package
|
// +k8s:deepcopy-gen=package
|
||||||
|
// +k8s:protobuf-gen=package
|
||||||
// +k8s:conversion-gen=k8s.io/metrics/pkg/apis/metrics
|
// +k8s:conversion-gen=k8s.io/metrics/pkg/apis/metrics
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,13 @@ filegroup(
|
||||||
":package-srcs",
|
":package-srcs",
|
||||||
"//vendor/gonum.org/v1/gonum/graph/encoding:all-srcs",
|
"//vendor/gonum.org/v1/gonum/graph/encoding:all-srcs",
|
||||||
"//vendor/gonum.org/v1/gonum/graph/formats/dot:all-srcs",
|
"//vendor/gonum.org/v1/gonum/graph/formats/dot:all-srcs",
|
||||||
|
"//vendor/gonum.org/v1/gonum/graph/internal/linear:all-srcs",
|
||||||
"//vendor/gonum.org/v1/gonum/graph/internal/ordered:all-srcs",
|
"//vendor/gonum.org/v1/gonum/graph/internal/ordered:all-srcs",
|
||||||
"//vendor/gonum.org/v1/gonum/graph/internal/set:all-srcs",
|
"//vendor/gonum.org/v1/gonum/graph/internal/set:all-srcs",
|
||||||
"//vendor/gonum.org/v1/gonum/graph/internal/uid:all-srcs",
|
"//vendor/gonum.org/v1/gonum/graph/internal/uid:all-srcs",
|
||||||
"//vendor/gonum.org/v1/gonum/graph/simple:all-srcs",
|
"//vendor/gonum.org/v1/gonum/graph/simple:all-srcs",
|
||||||
|
"//vendor/gonum.org/v1/gonum/graph/topo:all-srcs",
|
||||||
|
"//vendor/gonum.org/v1/gonum/graph/traverse:all-srcs",
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"doc.go",
|
||||||
|
"linear.go",
|
||||||
|
],
|
||||||
|
importmap = "k8s.io/kubernetes/vendor/gonum.org/v1/gonum/graph/internal/linear",
|
||||||
|
importpath = "gonum.org/v1/gonum/graph/internal/linear",
|
||||||
|
visibility = ["//vendor/gonum.org/v1/gonum/graph:__subpackages__"],
|
||||||
|
deps = ["//vendor/gonum.org/v1/gonum/graph:go_default_library"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
|
@ -0,0 +1,6 @@
|
||||||
|
// Copyright ©2017 The Gonum Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package linear provides common linear data structures.
|
||||||
|
package linear
|
|
@ -0,0 +1,73 @@
|
||||||
|
// Copyright ©2015 The Gonum Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package linear
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gonum.org/v1/gonum/graph"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NodeStack implements a LIFO stack of graph.Node.
|
||||||
|
type NodeStack []graph.Node
|
||||||
|
|
||||||
|
// Len returns the number of graph.Nodes on the stack.
|
||||||
|
func (s *NodeStack) Len() int { return len(*s) }
|
||||||
|
|
||||||
|
// Pop returns the last graph.Node on the stack and removes it
|
||||||
|
// from the stack.
|
||||||
|
func (s *NodeStack) Pop() graph.Node {
|
||||||
|
v := *s
|
||||||
|
v, n := v[:len(v)-1], v[len(v)-1]
|
||||||
|
*s = v
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push adds the node n to the stack at the last position.
|
||||||
|
func (s *NodeStack) Push(n graph.Node) { *s = append(*s, n) }
|
||||||
|
|
||||||
|
// NodeQueue implements a FIFO queue.
|
||||||
|
type NodeQueue struct {
|
||||||
|
head int
|
||||||
|
data []graph.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the number of graph.Nodes in the queue.
|
||||||
|
func (q *NodeQueue) Len() int { return len(q.data) - q.head }
|
||||||
|
|
||||||
|
// Enqueue adds the node n to the back of the queue.
|
||||||
|
func (q *NodeQueue) Enqueue(n graph.Node) {
|
||||||
|
if len(q.data) == cap(q.data) && q.head > 0 {
|
||||||
|
l := q.Len()
|
||||||
|
copy(q.data, q.data[q.head:])
|
||||||
|
q.head = 0
|
||||||
|
q.data = append(q.data[:l], n)
|
||||||
|
} else {
|
||||||
|
q.data = append(q.data, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dequeue returns the graph.Node at the front of the queue and
|
||||||
|
// removes it from the queue.
|
||||||
|
func (q *NodeQueue) Dequeue() graph.Node {
|
||||||
|
if q.Len() == 0 {
|
||||||
|
panic("queue: empty queue")
|
||||||
|
}
|
||||||
|
|
||||||
|
var n graph.Node
|
||||||
|
n, q.data[q.head] = q.data[q.head], nil
|
||||||
|
q.head++
|
||||||
|
|
||||||
|
if q.Len() == 0 {
|
||||||
|
q.head = 0
|
||||||
|
q.data = q.data[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset clears the queue for reuse.
|
||||||
|
func (q *NodeQueue) Reset() {
|
||||||
|
q.head = 0
|
||||||
|
q.data = q.data[:0]
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"bron_kerbosch.go",
|
||||||
|
"clique_graph.go",
|
||||||
|
"doc.go",
|
||||||
|
"johnson_cycles.go",
|
||||||
|
"non_tomita_choice.go",
|
||||||
|
"paton_cycles.go",
|
||||||
|
"tarjan.go",
|
||||||
|
"topo.go",
|
||||||
|
],
|
||||||
|
importmap = "k8s.io/kubernetes/vendor/gonum.org/v1/gonum/graph/topo",
|
||||||
|
importpath = "gonum.org/v1/gonum/graph/topo",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//vendor/gonum.org/v1/gonum/graph:go_default_library",
|
||||||
|
"//vendor/gonum.org/v1/gonum/graph/internal/linear:go_default_library",
|
||||||
|
"//vendor/gonum.org/v1/gonum/graph/internal/ordered:go_default_library",
|
||||||
|
"//vendor/gonum.org/v1/gonum/graph/internal/set:go_default_library",
|
||||||
|
"//vendor/gonum.org/v1/gonum/graph/traverse:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
|
@ -0,0 +1,250 @@
|
||||||
|
// Copyright ©2015 The Gonum Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package topo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gonum.org/v1/gonum/graph"
|
||||||
|
"gonum.org/v1/gonum/graph/internal/ordered"
|
||||||
|
"gonum.org/v1/gonum/graph/internal/set"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DegeneracyOrdering returns the degeneracy ordering and the k-cores of
|
||||||
|
// the undirected graph g.
|
||||||
|
func DegeneracyOrdering(g graph.Undirected) (order []graph.Node, cores [][]graph.Node) {
|
||||||
|
order, offsets := degeneracyOrdering(g)
|
||||||
|
|
||||||
|
ordered.Reverse(order)
|
||||||
|
cores = make([][]graph.Node, len(offsets))
|
||||||
|
offset := len(order)
|
||||||
|
for i, n := range offsets {
|
||||||
|
cores[i] = order[offset-n : offset]
|
||||||
|
offset -= n
|
||||||
|
}
|
||||||
|
return order, cores
|
||||||
|
}
|
||||||
|
|
||||||
|
// KCore returns the k-core of the undirected graph g with nodes in an
|
||||||
|
// optimal ordering for the coloring number.
|
||||||
|
func KCore(k int, g graph.Undirected) []graph.Node {
|
||||||
|
order, offsets := degeneracyOrdering(g)
|
||||||
|
|
||||||
|
var offset int
|
||||||
|
for _, n := range offsets[:k] {
|
||||||
|
offset += n
|
||||||
|
}
|
||||||
|
core := make([]graph.Node, len(order)-offset)
|
||||||
|
copy(core, order[offset:])
|
||||||
|
return core
|
||||||
|
}
|
||||||
|
|
||||||
|
// degeneracyOrdering is the common code for DegeneracyOrdering and KCore. It
|
||||||
|
// returns l, the nodes of g in optimal ordering for coloring number and
|
||||||
|
// s, a set of relative offsets into l for each k-core, where k is an index
|
||||||
|
// into s.
|
||||||
|
func degeneracyOrdering(g graph.Undirected) (l []graph.Node, s []int) {
|
||||||
|
nodes := g.Nodes()
|
||||||
|
|
||||||
|
// The algorithm used here is essentially as described at
|
||||||
|
// http://en.wikipedia.org/w/index.php?title=Degeneracy_%28graph_theory%29&oldid=640308710
|
||||||
|
|
||||||
|
// Initialize an output list L in return parameters.
|
||||||
|
|
||||||
|
// Compute a number d_v for each vertex v in G,
|
||||||
|
// the number of neighbors of v that are not already in L.
|
||||||
|
// Initially, these numbers are just the degrees of the vertices.
|
||||||
|
dv := make(map[int64]int, len(nodes))
|
||||||
|
var (
|
||||||
|
maxDegree int
|
||||||
|
neighbours = make(map[int64][]graph.Node)
|
||||||
|
)
|
||||||
|
for _, n := range nodes {
|
||||||
|
id := n.ID()
|
||||||
|
adj := g.From(id)
|
||||||
|
neighbours[id] = adj
|
||||||
|
dv[id] = len(adj)
|
||||||
|
if len(adj) > maxDegree {
|
||||||
|
maxDegree = len(adj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize an array D such that D[i] contains a list of the
|
||||||
|
// vertices v that are not already in L for which d_v = i.
|
||||||
|
d := make([][]graph.Node, maxDegree+1)
|
||||||
|
for _, n := range nodes {
|
||||||
|
deg := dv[n.ID()]
|
||||||
|
d[deg] = append(d[deg], n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize k to 0.
|
||||||
|
k := 0
|
||||||
|
// Repeat n times:
|
||||||
|
s = []int{0}
|
||||||
|
for range nodes {
|
||||||
|
// Scan the array cells D[0], D[1], ... until
|
||||||
|
// finding an i for which D[i] is nonempty.
|
||||||
|
var (
|
||||||
|
i int
|
||||||
|
di []graph.Node
|
||||||
|
)
|
||||||
|
for i, di = range d {
|
||||||
|
if len(di) != 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set k to max(k,i).
|
||||||
|
if i > k {
|
||||||
|
k = i
|
||||||
|
s = append(s, make([]int, k-len(s)+1)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select a vertex v from D[i]. Add v to the
|
||||||
|
// beginning of L and remove it from D[i].
|
||||||
|
var v graph.Node
|
||||||
|
v, d[i] = di[len(di)-1], di[:len(di)-1]
|
||||||
|
l = append(l, v)
|
||||||
|
s[k]++
|
||||||
|
delete(dv, v.ID())
|
||||||
|
|
||||||
|
// For each neighbor w of v not already in L,
|
||||||
|
// subtract one from d_w and move w to the
|
||||||
|
// cell of D corresponding to the new value of d_w.
|
||||||
|
for _, w := range neighbours[v.ID()] {
|
||||||
|
dw, ok := dv[w.ID()]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for i, n := range d[dw] {
|
||||||
|
if n.ID() == w.ID() {
|
||||||
|
d[dw][i], d[dw] = d[dw][len(d[dw])-1], d[dw][:len(d[dw])-1]
|
||||||
|
dw--
|
||||||
|
d[dw] = append(d[dw], w)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dv[w.ID()] = dw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return l, s
|
||||||
|
}
|
||||||
|
|
||||||
|
// BronKerbosch returns the set of maximal cliques of the undirected graph g.
|
||||||
|
func BronKerbosch(g graph.Undirected) [][]graph.Node {
|
||||||
|
nodes := g.Nodes()
|
||||||
|
|
||||||
|
// The algorithm used here is essentially BronKerbosch3 as described at
|
||||||
|
// http://en.wikipedia.org/w/index.php?title=Bron%E2%80%93Kerbosch_algorithm&oldid=656805858
|
||||||
|
|
||||||
|
p := make(set.Nodes, len(nodes))
|
||||||
|
for _, n := range nodes {
|
||||||
|
p.Add(n)
|
||||||
|
}
|
||||||
|
x := make(set.Nodes)
|
||||||
|
var bk bronKerbosch
|
||||||
|
order, _ := degeneracyOrdering(g)
|
||||||
|
ordered.Reverse(order)
|
||||||
|
for _, v := range order {
|
||||||
|
neighbours := g.From(v.ID())
|
||||||
|
nv := make(set.Nodes, len(neighbours))
|
||||||
|
for _, n := range neighbours {
|
||||||
|
nv.Add(n)
|
||||||
|
}
|
||||||
|
bk.maximalCliquePivot(g, []graph.Node{v}, make(set.Nodes).Intersect(p, nv), make(set.Nodes).Intersect(x, nv))
|
||||||
|
p.Remove(v)
|
||||||
|
x.Add(v)
|
||||||
|
}
|
||||||
|
return bk
|
||||||
|
}
|
||||||
|
|
||||||
|
type bronKerbosch [][]graph.Node
|
||||||
|
|
||||||
|
func (bk *bronKerbosch) maximalCliquePivot(g graph.Undirected, r []graph.Node, p, x set.Nodes) {
|
||||||
|
if len(p) == 0 && len(x) == 0 {
|
||||||
|
*bk = append(*bk, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neighbours := bk.choosePivotFrom(g, p, x)
|
||||||
|
nu := make(set.Nodes, len(neighbours))
|
||||||
|
for _, n := range neighbours {
|
||||||
|
nu.Add(n)
|
||||||
|
}
|
||||||
|
for _, v := range p {
|
||||||
|
if nu.Has(v) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
vid := v.ID()
|
||||||
|
neighbours := g.From(vid)
|
||||||
|
nv := make(set.Nodes, len(neighbours))
|
||||||
|
for _, n := range neighbours {
|
||||||
|
nv.Add(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
var found bool
|
||||||
|
for _, n := range r {
|
||||||
|
if n.ID() == vid {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var sr []graph.Node
|
||||||
|
if !found {
|
||||||
|
sr = append(r[:len(r):len(r)], v)
|
||||||
|
}
|
||||||
|
|
||||||
|
bk.maximalCliquePivot(g, sr, make(set.Nodes).Intersect(p, nv), make(set.Nodes).Intersect(x, nv))
|
||||||
|
p.Remove(v)
|
||||||
|
x.Add(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*bronKerbosch) choosePivotFrom(g graph.Undirected, p, x set.Nodes) (neighbors []graph.Node) {
|
||||||
|
// TODO(kortschak): Investigate the impact of pivot choice that maximises
|
||||||
|
// |p ⋂ neighbours(u)| as a function of input size. Until then, leave as
|
||||||
|
// compile time option.
|
||||||
|
if !tomitaTanakaTakahashi {
|
||||||
|
for _, n := range p {
|
||||||
|
return g.From(n.ID())
|
||||||
|
}
|
||||||
|
for _, n := range x {
|
||||||
|
return g.From(n.ID())
|
||||||
|
}
|
||||||
|
panic("bronKerbosch: empty set")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
max = -1
|
||||||
|
pivot graph.Node
|
||||||
|
)
|
||||||
|
maxNeighbors := func(s set.Nodes) {
|
||||||
|
outer:
|
||||||
|
for _, u := range s {
|
||||||
|
nb := g.From(u.ID())
|
||||||
|
c := len(nb)
|
||||||
|
if c <= max {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for n := range nb {
|
||||||
|
if _, ok := p[int64(n)]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c--
|
||||||
|
if c <= max {
|
||||||
|
continue outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
max = c
|
||||||
|
pivot = u
|
||||||
|
neighbors = nb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maxNeighbors(p)
|
||||||
|
maxNeighbors(x)
|
||||||
|
if pivot == nil {
|
||||||
|
panic("bronKerbosch: empty set")
|
||||||
|
}
|
||||||
|
return neighbors
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
// Copyright ©2017 The Gonum Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package topo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"gonum.org/v1/gonum/graph"
|
||||||
|
"gonum.org/v1/gonum/graph/internal/ordered"
|
||||||
|
"gonum.org/v1/gonum/graph/internal/set"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Builder is a pure topological graph construction type.
|
||||||
|
type Builder interface {
|
||||||
|
AddNode(graph.Node)
|
||||||
|
SetEdge(graph.Edge)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CliqueGraph builds the clique graph of g in dst using Clique and CliqueGraphEdge
|
||||||
|
// nodes and edges. The nodes returned by calls to Nodes on the nodes and edges of
|
||||||
|
// the constructed graph are the cliques and the common nodes between cliques
|
||||||
|
// respectively. The dst graph is not cleared.
|
||||||
|
func CliqueGraph(dst Builder, g graph.Undirected) {
|
||||||
|
cliques := BronKerbosch(g)
|
||||||
|
|
||||||
|
// Construct a consistent view of cliques in g. Sorting costs
|
||||||
|
// us a little, but not as much as the cliques themselves.
|
||||||
|
for _, c := range cliques {
|
||||||
|
sort.Sort(ordered.ByID(c))
|
||||||
|
}
|
||||||
|
sort.Sort(ordered.BySliceIDs(cliques))
|
||||||
|
|
||||||
|
cliqueNodes := make(cliqueNodeSets, len(cliques))
|
||||||
|
for id, c := range cliques {
|
||||||
|
s := make(set.Nodes, len(c))
|
||||||
|
for _, n := range c {
|
||||||
|
s.Add(n)
|
||||||
|
}
|
||||||
|
ns := &nodeSet{Clique: Clique{id: int64(id), nodes: c}, nodes: s}
|
||||||
|
dst.AddNode(ns.Clique)
|
||||||
|
for _, n := range c {
|
||||||
|
nid := n.ID()
|
||||||
|
cliqueNodes[nid] = append(cliqueNodes[nid], ns)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cliques := range cliqueNodes {
|
||||||
|
for i, uc := range cliques {
|
||||||
|
for _, vc := range cliques[i+1:] {
|
||||||
|
// Retain the nodes that contribute to the
|
||||||
|
// edge between the cliques.
|
||||||
|
var edgeNodes []graph.Node
|
||||||
|
switch 1 {
|
||||||
|
case len(uc.Clique.nodes):
|
||||||
|
edgeNodes = []graph.Node{uc.Clique.nodes[0]}
|
||||||
|
case len(vc.Clique.nodes):
|
||||||
|
edgeNodes = []graph.Node{vc.Clique.nodes[0]}
|
||||||
|
default:
|
||||||
|
for _, n := range make(set.Nodes).Intersect(uc.nodes, vc.nodes) {
|
||||||
|
edgeNodes = append(edgeNodes, n)
|
||||||
|
}
|
||||||
|
sort.Sort(ordered.ByID(edgeNodes))
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.SetEdge(CliqueGraphEdge{from: uc.Clique, to: vc.Clique, nodes: edgeNodes})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type cliqueNodeSets map[int64][]*nodeSet
|
||||||
|
|
||||||
|
type nodeSet struct {
|
||||||
|
Clique
|
||||||
|
nodes set.Nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clique is a node in a clique graph.
|
||||||
|
type Clique struct {
|
||||||
|
id int64
|
||||||
|
nodes []graph.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID returns the node ID.
|
||||||
|
func (n Clique) ID() int64 { return n.id }
|
||||||
|
|
||||||
|
// Nodes returns the nodes in the clique.
|
||||||
|
func (n Clique) Nodes() []graph.Node { return n.nodes }
|
||||||
|
|
||||||
|
// CliqueGraphEdge is an edge in a clique graph.
|
||||||
|
type CliqueGraphEdge struct {
|
||||||
|
from, to Clique
|
||||||
|
nodes []graph.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
// From returns the from node of the edge.
|
||||||
|
func (e CliqueGraphEdge) From() graph.Node { return e.from }
|
||||||
|
|
||||||
|
// To returns the to node of the edge.
|
||||||
|
func (e CliqueGraphEdge) To() graph.Node { return e.to }
|
||||||
|
|
||||||
|
// Nodes returns the common nodes in the cliques of the underlying graph
|
||||||
|
// corresponding to the from and to nodes in the clique graph.
|
||||||
|
func (e CliqueGraphEdge) Nodes() []graph.Node { return e.nodes }
|
|
@ -0,0 +1,6 @@
|
||||||
|
// Copyright ©2017 The Gonum Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package topo provides graph topology analysis functions.
|
||||||
|
package topo
|
|
@ -0,0 +1,281 @@
|
||||||
|
// Copyright ©2015 The Gonum Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package topo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"gonum.org/v1/gonum/graph"
|
||||||
|
"gonum.org/v1/gonum/graph/internal/ordered"
|
||||||
|
"gonum.org/v1/gonum/graph/internal/set"
|
||||||
|
)
|
||||||
|
|
||||||
|
// johnson implements Johnson's "Finding all the elementary
|
||||||
|
// circuits of a directed graph" algorithm. SIAM J. Comput. 4(1):1975.
|
||||||
|
//
|
||||||
|
// Comments in the johnson methods are kept in sync with the comments
|
||||||
|
// and labels from the paper.
|
||||||
|
type johnson struct {
|
||||||
|
adjacent johnsonGraph // SCC adjacency list.
|
||||||
|
b []set.Ints // Johnson's "B-list".
|
||||||
|
blocked []bool
|
||||||
|
s int
|
||||||
|
|
||||||
|
stack []graph.Node
|
||||||
|
|
||||||
|
result [][]graph.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
// DirectedCyclesIn returns the set of elementary cycles in the graph g.
|
||||||
|
func DirectedCyclesIn(g graph.Directed) [][]graph.Node {
|
||||||
|
jg := johnsonGraphFrom(g)
|
||||||
|
j := johnson{
|
||||||
|
adjacent: jg,
|
||||||
|
b: make([]set.Ints, len(jg.orig)),
|
||||||
|
blocked: make([]bool, len(jg.orig)),
|
||||||
|
}
|
||||||
|
|
||||||
|
// len(j.nodes) is the order of g.
|
||||||
|
for j.s < len(j.adjacent.orig)-1 {
|
||||||
|
// We use the previous SCC adjacency to reduce the work needed.
|
||||||
|
sccs := TarjanSCC(j.adjacent.subgraph(j.s))
|
||||||
|
// A_k = adjacency structure of strong component K with least
|
||||||
|
// vertex in subgraph of G induced by {s, s+1, ... ,n}.
|
||||||
|
j.adjacent = j.adjacent.sccSubGraph(sccs, 2) // Only allow SCCs with >= 2 vertices.
|
||||||
|
if j.adjacent.order() == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// s = least vertex in V_k
|
||||||
|
if s := j.adjacent.leastVertexIndex(); s < j.s {
|
||||||
|
j.s = s
|
||||||
|
}
|
||||||
|
for i, v := range j.adjacent.orig {
|
||||||
|
if !j.adjacent.nodes.Has(v.ID()) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(j.adjacent.succ[v.ID()]) > 0 {
|
||||||
|
j.blocked[i] = false
|
||||||
|
j.b[i] = make(set.Ints)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//L3:
|
||||||
|
_ = j.circuit(j.s)
|
||||||
|
j.s++
|
||||||
|
}
|
||||||
|
|
||||||
|
return j.result
|
||||||
|
}
|
||||||
|
|
||||||
|
// circuit is the CIRCUIT sub-procedure in the paper.
|
||||||
|
func (j *johnson) circuit(v int) bool {
|
||||||
|
f := false
|
||||||
|
n := j.adjacent.orig[v]
|
||||||
|
j.stack = append(j.stack, n)
|
||||||
|
j.blocked[v] = true
|
||||||
|
|
||||||
|
//L1:
|
||||||
|
for w := range j.adjacent.succ[n.ID()] {
|
||||||
|
w := j.adjacent.indexOf(w)
|
||||||
|
if w == j.s {
|
||||||
|
// Output circuit composed of stack followed by s.
|
||||||
|
r := make([]graph.Node, len(j.stack)+1)
|
||||||
|
copy(r, j.stack)
|
||||||
|
r[len(r)-1] = j.adjacent.orig[j.s]
|
||||||
|
j.result = append(j.result, r)
|
||||||
|
f = true
|
||||||
|
} else if !j.blocked[w] {
|
||||||
|
if j.circuit(w) {
|
||||||
|
f = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//L2:
|
||||||
|
if f {
|
||||||
|
j.unblock(v)
|
||||||
|
} else {
|
||||||
|
for w := range j.adjacent.succ[n.ID()] {
|
||||||
|
j.b[j.adjacent.indexOf(w)].Add(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j.stack = j.stack[:len(j.stack)-1]
|
||||||
|
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// unblock is the UNBLOCK sub-procedure in the paper.
|
||||||
|
func (j *johnson) unblock(u int) {
|
||||||
|
j.blocked[u] = false
|
||||||
|
for w := range j.b[u] {
|
||||||
|
j.b[u].Remove(w)
|
||||||
|
if j.blocked[w] {
|
||||||
|
j.unblock(w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// johnsonGraph is an edge list representation of a graph with helpers
|
||||||
|
// necessary for Johnson's algorithm
|
||||||
|
type johnsonGraph struct {
|
||||||
|
// Keep the original graph nodes and a
|
||||||
|
// look-up to into the non-sparse
|
||||||
|
// collection of potentially sparse IDs.
|
||||||
|
orig []graph.Node
|
||||||
|
index map[int64]int
|
||||||
|
|
||||||
|
nodes set.Int64s
|
||||||
|
succ map[int64]set.Int64s
|
||||||
|
}
|
||||||
|
|
||||||
|
// johnsonGraphFrom returns a deep copy of the graph g.
|
||||||
|
func johnsonGraphFrom(g graph.Directed) johnsonGraph {
|
||||||
|
nodes := g.Nodes()
|
||||||
|
sort.Sort(ordered.ByID(nodes))
|
||||||
|
c := johnsonGraph{
|
||||||
|
orig: nodes,
|
||||||
|
index: make(map[int64]int, len(nodes)),
|
||||||
|
|
||||||
|
nodes: make(set.Int64s, len(nodes)),
|
||||||
|
succ: make(map[int64]set.Int64s),
|
||||||
|
}
|
||||||
|
for i, u := range nodes {
|
||||||
|
uid := u.ID()
|
||||||
|
c.index[uid] = i
|
||||||
|
for _, v := range g.From(uid) {
|
||||||
|
if c.succ[uid] == nil {
|
||||||
|
c.succ[uid] = make(set.Int64s)
|
||||||
|
c.nodes.Add(uid)
|
||||||
|
}
|
||||||
|
c.nodes.Add(v.ID())
|
||||||
|
c.succ[uid].Add(v.ID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// order returns the order of the graph.
|
||||||
|
func (g johnsonGraph) order() int { return g.nodes.Count() }
|
||||||
|
|
||||||
|
// indexOf returns the index of the retained node for the given node ID.
|
||||||
|
func (g johnsonGraph) indexOf(id int64) int {
|
||||||
|
return g.index[id]
|
||||||
|
}
|
||||||
|
|
||||||
|
// leastVertexIndex returns the index into orig of the least vertex.
|
||||||
|
func (g johnsonGraph) leastVertexIndex() int {
|
||||||
|
for _, v := range g.orig {
|
||||||
|
if g.nodes.Has(v.ID()) {
|
||||||
|
return g.indexOf(v.ID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("johnsonCycles: empty set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// subgraph returns a subgraph of g induced by {s, s+1, ... , n}. The
|
||||||
|
// subgraph is destructively generated in g.
|
||||||
|
func (g johnsonGraph) subgraph(s int) johnsonGraph {
|
||||||
|
sn := g.orig[s].ID()
|
||||||
|
for u, e := range g.succ {
|
||||||
|
if u < sn {
|
||||||
|
g.nodes.Remove(u)
|
||||||
|
delete(g.succ, u)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for v := range e {
|
||||||
|
if v < sn {
|
||||||
|
g.succ[u].Remove(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
// sccSubGraph returns the graph of the tarjan's strongly connected
|
||||||
|
// components with each SCC containing at least min vertices.
|
||||||
|
// sccSubGraph returns nil if there is no SCC with at least min
|
||||||
|
// members.
|
||||||
|
func (g johnsonGraph) sccSubGraph(sccs [][]graph.Node, min int) johnsonGraph {
|
||||||
|
if len(g.nodes) == 0 {
|
||||||
|
g.nodes = nil
|
||||||
|
g.succ = nil
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
sub := johnsonGraph{
|
||||||
|
orig: g.orig,
|
||||||
|
index: g.index,
|
||||||
|
nodes: make(set.Int64s),
|
||||||
|
succ: make(map[int64]set.Int64s),
|
||||||
|
}
|
||||||
|
|
||||||
|
var n int
|
||||||
|
for _, scc := range sccs {
|
||||||
|
if len(scc) < min {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
n++
|
||||||
|
for _, u := range scc {
|
||||||
|
for _, v := range scc {
|
||||||
|
if _, ok := g.succ[u.ID()][v.ID()]; ok {
|
||||||
|
if sub.succ[u.ID()] == nil {
|
||||||
|
sub.succ[u.ID()] = make(set.Int64s)
|
||||||
|
sub.nodes.Add(u.ID())
|
||||||
|
}
|
||||||
|
sub.nodes.Add(v.ID())
|
||||||
|
sub.succ[u.ID()].Add(v.ID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
g.nodes = nil
|
||||||
|
g.succ = nil
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
return sub
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nodes is required to satisfy Tarjan.
|
||||||
|
func (g johnsonGraph) Nodes() []graph.Node {
|
||||||
|
n := make([]graph.Node, 0, len(g.nodes))
|
||||||
|
for id := range g.nodes {
|
||||||
|
n = append(n, johnsonGraphNode(id))
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// Successors is required to satisfy Tarjan.
|
||||||
|
func (g johnsonGraph) From(id int64) []graph.Node {
|
||||||
|
adj := g.succ[id]
|
||||||
|
if len(adj) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
succ := make([]graph.Node, 0, len(adj))
|
||||||
|
for id := range adj {
|
||||||
|
succ = append(succ, johnsonGraphNode(id))
|
||||||
|
}
|
||||||
|
return succ
|
||||||
|
}
|
||||||
|
|
||||||
|
func (johnsonGraph) Has(int64) bool {
|
||||||
|
panic("topo: unintended use of johnsonGraph")
|
||||||
|
}
|
||||||
|
func (johnsonGraph) HasEdgeBetween(_, _ int64) bool {
|
||||||
|
panic("topo: unintended use of johnsonGraph")
|
||||||
|
}
|
||||||
|
func (johnsonGraph) Edge(_, _ int64) graph.Edge {
|
||||||
|
panic("topo: unintended use of johnsonGraph")
|
||||||
|
}
|
||||||
|
func (johnsonGraph) HasEdgeFromTo(_, _ int64) bool {
|
||||||
|
panic("topo: unintended use of johnsonGraph")
|
||||||
|
}
|
||||||
|
func (johnsonGraph) To(int64) []graph.Node {
|
||||||
|
panic("topo: unintended use of johnsonGraph")
|
||||||
|
}
|
||||||
|
|
||||||
|
type johnsonGraphNode int64
|
||||||
|
|
||||||
|
func (n johnsonGraphNode) ID() int64 { return int64(n) }
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Copyright ©2015 The Gonum Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !tomita
|
||||||
|
|
||||||
|
package topo
|
||||||
|
|
||||||
|
const tomitaTanakaTakahashi = false
|
|
@ -0,0 +1,81 @@
|
||||||
|
// Copyright ©2017 The Gonum Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package topo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gonum.org/v1/gonum/graph"
|
||||||
|
"gonum.org/v1/gonum/graph/internal/linear"
|
||||||
|
"gonum.org/v1/gonum/graph/internal/set"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UndirectedCyclesIn returns a set of cycles that forms a cycle basis in the graph g.
|
||||||
|
// Any cycle in g can be constructed as a symmetric difference of its elements.
|
||||||
|
func UndirectedCyclesIn(g graph.Undirected) [][]graph.Node {
|
||||||
|
// From "An algorithm for finding a fundamental set of cycles of a graph"
|
||||||
|
// https://doi.org/10.1145/363219.363232
|
||||||
|
|
||||||
|
var cycles [][]graph.Node
|
||||||
|
done := make(set.Int64s)
|
||||||
|
var tree linear.NodeStack
|
||||||
|
for _, n := range g.Nodes() {
|
||||||
|
id := n.ID()
|
||||||
|
if done.Has(id) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
done.Add(id)
|
||||||
|
|
||||||
|
tree = tree[:0]
|
||||||
|
tree.Push(n)
|
||||||
|
from := sets{id: set.Int64s{}}
|
||||||
|
to := map[int64]graph.Node{id: n}
|
||||||
|
|
||||||
|
for tree.Len() != 0 {
|
||||||
|
u := tree.Pop()
|
||||||
|
uid := u.ID()
|
||||||
|
adj := from[uid]
|
||||||
|
for _, v := range g.From(uid) {
|
||||||
|
vid := v.ID()
|
||||||
|
switch {
|
||||||
|
case uid == vid:
|
||||||
|
cycles = append(cycles, []graph.Node{u})
|
||||||
|
case !from.has(vid):
|
||||||
|
done.Add(vid)
|
||||||
|
to[vid] = u
|
||||||
|
tree.Push(v)
|
||||||
|
from.add(uid, vid)
|
||||||
|
case !adj.Has(vid):
|
||||||
|
c := []graph.Node{v, u}
|
||||||
|
adj := from[vid]
|
||||||
|
p := to[uid]
|
||||||
|
for !adj.Has(p.ID()) {
|
||||||
|
c = append(c, p)
|
||||||
|
p = to[p.ID()]
|
||||||
|
}
|
||||||
|
c = append(c, p, c[0])
|
||||||
|
cycles = append(cycles, c)
|
||||||
|
adj.Add(uid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cycles
|
||||||
|
}
|
||||||
|
|
||||||
|
type sets map[int64]set.Int64s
|
||||||
|
|
||||||
|
func (s sets) add(uid, vid int64) {
|
||||||
|
e, ok := s[vid]
|
||||||
|
if !ok {
|
||||||
|
e = make(set.Int64s)
|
||||||
|
s[vid] = e
|
||||||
|
}
|
||||||
|
e.Add(uid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s sets) has(uid int64) bool {
|
||||||
|
_, ok := s[uid]
|
||||||
|
return ok
|
||||||
|
}
|
|
@ -0,0 +1,197 @@
|
||||||
|
// Copyright ©2015 The Gonum Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package topo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"gonum.org/v1/gonum/graph"
|
||||||
|
"gonum.org/v1/gonum/graph/internal/ordered"
|
||||||
|
"gonum.org/v1/gonum/graph/internal/set"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unorderable is an error containing sets of unorderable graph.Nodes.
|
||||||
|
type Unorderable [][]graph.Node
|
||||||
|
|
||||||
|
// Error satisfies the error interface.
|
||||||
|
func (e Unorderable) Error() string {
|
||||||
|
const maxNodes = 10
|
||||||
|
var n int
|
||||||
|
for _, c := range e {
|
||||||
|
n += len(c)
|
||||||
|
}
|
||||||
|
if n > maxNodes {
|
||||||
|
// Don't return errors that are too long.
|
||||||
|
return fmt.Sprintf("topo: no topological ordering: %d nodes in %d cyclic components", n, len(e))
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("topo: no topological ordering: cyclic components: %v", [][]graph.Node(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
func lexical(nodes []graph.Node) { sort.Sort(ordered.ByID(nodes)) }
|
||||||
|
|
||||||
|
// Sort performs a topological sort of the directed graph g returning the 'from' to 'to'
|
||||||
|
// sort order. If a topological ordering is not possible, an Unorderable error is returned
|
||||||
|
// listing cyclic components in g with each cyclic component's members sorted by ID. When
|
||||||
|
// an Unorderable error is returned, each cyclic component's topological position within
|
||||||
|
// the sorted nodes is marked with a nil graph.Node.
|
||||||
|
func Sort(g graph.Directed) (sorted []graph.Node, err error) {
|
||||||
|
sccs := TarjanSCC(g)
|
||||||
|
return sortedFrom(sccs, lexical)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SortStabilized performs a topological sort of the directed graph g returning the 'from'
|
||||||
|
// to 'to' sort order, or the order defined by the in place order sort function where there
|
||||||
|
// is no unambiguous topological ordering. If a topological ordering is not possible, an
|
||||||
|
// Unorderable error is returned listing cyclic components in g with each cyclic component's
|
||||||
|
// members sorted by the provided order function. If order is nil, nodes are ordered lexically
|
||||||
|
// by node ID. When an Unorderable error is returned, each cyclic component's topological
|
||||||
|
// position within the sorted nodes is marked with a nil graph.Node.
|
||||||
|
func SortStabilized(g graph.Directed, order func([]graph.Node)) (sorted []graph.Node, err error) {
|
||||||
|
if order == nil {
|
||||||
|
order = lexical
|
||||||
|
}
|
||||||
|
sccs := tarjanSCCstabilized(g, order)
|
||||||
|
return sortedFrom(sccs, order)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sortedFrom(sccs [][]graph.Node, order func([]graph.Node)) ([]graph.Node, error) {
|
||||||
|
sorted := make([]graph.Node, 0, len(sccs))
|
||||||
|
var sc Unorderable
|
||||||
|
for _, s := range sccs {
|
||||||
|
if len(s) != 1 {
|
||||||
|
order(s)
|
||||||
|
sc = append(sc, s)
|
||||||
|
sorted = append(sorted, nil)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sorted = append(sorted, s[0])
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
if sc != nil {
|
||||||
|
for i, j := 0, len(sc)-1; i < j; i, j = i+1, j-1 {
|
||||||
|
sc[i], sc[j] = sc[j], sc[i]
|
||||||
|
}
|
||||||
|
err = sc
|
||||||
|
}
|
||||||
|
ordered.Reverse(sorted)
|
||||||
|
return sorted, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TarjanSCC returns the strongly connected components of the graph g using Tarjan's algorithm.
|
||||||
|
//
|
||||||
|
// A strongly connected component of a graph is a set of vertices where it's possible to reach any
|
||||||
|
// vertex in the set from any other (meaning there's a cycle between them.)
|
||||||
|
//
|
||||||
|
// Generally speaking, a directed graph where the number of strongly connected components is equal
|
||||||
|
// to the number of nodes is acyclic, unless you count reflexive edges as a cycle (which requires
|
||||||
|
// only a little extra testing.)
|
||||||
|
//
|
||||||
|
func TarjanSCC(g graph.Directed) [][]graph.Node {
|
||||||
|
return tarjanSCCstabilized(g, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func tarjanSCCstabilized(g graph.Directed, order func([]graph.Node)) [][]graph.Node {
|
||||||
|
nodes := g.Nodes()
|
||||||
|
var succ func(id int64) []graph.Node
|
||||||
|
if order == nil {
|
||||||
|
succ = g.From
|
||||||
|
} else {
|
||||||
|
order(nodes)
|
||||||
|
ordered.Reverse(nodes)
|
||||||
|
|
||||||
|
succ = func(id int64) []graph.Node {
|
||||||
|
to := g.From(id)
|
||||||
|
order(to)
|
||||||
|
ordered.Reverse(to)
|
||||||
|
return to
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t := tarjan{
|
||||||
|
succ: succ,
|
||||||
|
|
||||||
|
indexTable: make(map[int64]int, len(nodes)),
|
||||||
|
lowLink: make(map[int64]int, len(nodes)),
|
||||||
|
onStack: make(set.Int64s),
|
||||||
|
}
|
||||||
|
for _, v := range nodes {
|
||||||
|
if t.indexTable[v.ID()] == 0 {
|
||||||
|
t.strongconnect(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t.sccs
|
||||||
|
}
|
||||||
|
|
||||||
|
// tarjan implements Tarjan's strongly connected component finding
|
||||||
|
// algorithm. The implementation is from the pseudocode at
|
||||||
|
//
|
||||||
|
// http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm?oldid=642744644
|
||||||
|
//
|
||||||
|
type tarjan struct {
|
||||||
|
succ func(id int64) []graph.Node
|
||||||
|
|
||||||
|
index int
|
||||||
|
indexTable map[int64]int
|
||||||
|
lowLink map[int64]int
|
||||||
|
onStack set.Int64s
|
||||||
|
|
||||||
|
stack []graph.Node
|
||||||
|
|
||||||
|
sccs [][]graph.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
// strongconnect is the strongconnect function described in the
|
||||||
|
// wikipedia article.
|
||||||
|
func (t *tarjan) strongconnect(v graph.Node) {
|
||||||
|
vID := v.ID()
|
||||||
|
|
||||||
|
// Set the depth index for v to the smallest unused index.
|
||||||
|
t.index++
|
||||||
|
t.indexTable[vID] = t.index
|
||||||
|
t.lowLink[vID] = t.index
|
||||||
|
t.stack = append(t.stack, v)
|
||||||
|
t.onStack.Add(vID)
|
||||||
|
|
||||||
|
// Consider successors of v.
|
||||||
|
for _, w := range t.succ(vID) {
|
||||||
|
wID := w.ID()
|
||||||
|
if t.indexTable[wID] == 0 {
|
||||||
|
// Successor w has not yet been visited; recur on it.
|
||||||
|
t.strongconnect(w)
|
||||||
|
t.lowLink[vID] = min(t.lowLink[vID], t.lowLink[wID])
|
||||||
|
} else if t.onStack.Has(wID) {
|
||||||
|
// Successor w is in stack s and hence in the current SCC.
|
||||||
|
t.lowLink[vID] = min(t.lowLink[vID], t.indexTable[wID])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If v is a root node, pop the stack and generate an SCC.
|
||||||
|
if t.lowLink[vID] == t.indexTable[vID] {
|
||||||
|
// Start a new strongly connected component.
|
||||||
|
var (
|
||||||
|
scc []graph.Node
|
||||||
|
w graph.Node
|
||||||
|
)
|
||||||
|
for {
|
||||||
|
w, t.stack = t.stack[len(t.stack)-1], t.stack[:len(t.stack)-1]
|
||||||
|
t.onStack.Remove(w.ID())
|
||||||
|
// Add w to current strongly connected component.
|
||||||
|
scc = append(scc, w)
|
||||||
|
if w.ID() == vID {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Output the current strongly connected component.
|
||||||
|
t.sccs = append(t.sccs, scc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func min(a, b int) int {
|
||||||
|
if a < b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Copyright ©2015 The Gonum Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build tomita
|
||||||
|
|
||||||
|
package topo
|
||||||
|
|
||||||
|
const tomitaTanakaTakahashi = true
|
|
@ -0,0 +1,68 @@
|
||||||
|
// Copyright ©2014 The Gonum Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package topo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gonum.org/v1/gonum/graph"
|
||||||
|
"gonum.org/v1/gonum/graph/traverse"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsPathIn returns whether path is a path in g.
|
||||||
|
//
|
||||||
|
// As special cases, IsPathIn returns true for a zero length path or for
|
||||||
|
// a path of length 1 when the node in path exists in the graph.
|
||||||
|
func IsPathIn(g graph.Graph, path []graph.Node) bool {
|
||||||
|
switch len(path) {
|
||||||
|
case 0:
|
||||||
|
return true
|
||||||
|
case 1:
|
||||||
|
return g.Has(path[0].ID())
|
||||||
|
default:
|
||||||
|
var canReach func(uid, vid int64) bool
|
||||||
|
switch g := g.(type) {
|
||||||
|
case graph.Directed:
|
||||||
|
canReach = g.HasEdgeFromTo
|
||||||
|
default:
|
||||||
|
canReach = g.HasEdgeBetween
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, u := range path[:len(path)-1] {
|
||||||
|
if !canReach(u.ID(), path[i+1].ID()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PathExistsIn returns whether there is a path in g starting at from extending
|
||||||
|
// to to.
|
||||||
|
//
|
||||||
|
// PathExistsIn exists as a helper function. If many tests for path existence
|
||||||
|
// are being performed, other approaches will be more efficient.
|
||||||
|
func PathExistsIn(g graph.Graph, from, to graph.Node) bool {
|
||||||
|
var t traverse.BreadthFirst
|
||||||
|
return t.Walk(g, from, func(n graph.Node, _ int) bool { return n.ID() == to.ID() }) != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConnectedComponents returns the connected components of the undirected graph g.
|
||||||
|
func ConnectedComponents(g graph.Undirected) [][]graph.Node {
|
||||||
|
var (
|
||||||
|
w traverse.DepthFirst
|
||||||
|
c []graph.Node
|
||||||
|
cc [][]graph.Node
|
||||||
|
)
|
||||||
|
during := func(n graph.Node) {
|
||||||
|
c = append(c, n)
|
||||||
|
}
|
||||||
|
after := func() {
|
||||||
|
cc = append(cc, []graph.Node(nil))
|
||||||
|
cc[len(cc)-1] = append(cc[len(cc)-1], c...)
|
||||||
|
c = c[:0]
|
||||||
|
}
|
||||||
|
w.WalkAll(g, nil, after, during)
|
||||||
|
|
||||||
|
return cc
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"doc.go",
|
||||||
|
"traverse.go",
|
||||||
|
],
|
||||||
|
importmap = "k8s.io/kubernetes/vendor/gonum.org/v1/gonum/graph/traverse",
|
||||||
|
importpath = "gonum.org/v1/gonum/graph/traverse",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//vendor/gonum.org/v1/gonum/graph:go_default_library",
|
||||||
|
"//vendor/gonum.org/v1/gonum/graph/internal/linear:go_default_library",
|
||||||
|
"//vendor/gonum.org/v1/gonum/graph/internal/set:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
|
@ -0,0 +1,6 @@
|
||||||
|
// Copyright ©2017 The Gonum Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package traverse provides basic graph traversal primitives.
|
||||||
|
package traverse
|
|
@ -0,0 +1,199 @@
|
||||||
|
// Copyright ©2015 The Gonum Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package traverse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gonum.org/v1/gonum/graph"
|
||||||
|
"gonum.org/v1/gonum/graph/internal/linear"
|
||||||
|
"gonum.org/v1/gonum/graph/internal/set"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ Graph = graph.Graph(nil)
|
||||||
|
|
||||||
|
// Graph is the subset of graph.Graph necessary for graph traversal.
|
||||||
|
type Graph interface {
|
||||||
|
// From returns all nodes that can be reached directly
|
||||||
|
// from the node with the given ID.
|
||||||
|
From(id int64) []graph.Node
|
||||||
|
|
||||||
|
// Edge returns the edge from u to v, with IDs uid and vid,
|
||||||
|
// if such an edge exists and nil otherwise. The node v
|
||||||
|
// must be directly reachable from u as defined by the
|
||||||
|
// From method.
|
||||||
|
Edge(uid, vid int64) graph.Edge
|
||||||
|
}
|
||||||
|
|
||||||
|
// BreadthFirst implements stateful breadth-first graph traversal.
|
||||||
|
type BreadthFirst struct {
|
||||||
|
EdgeFilter func(graph.Edge) bool
|
||||||
|
Visit func(u, v graph.Node)
|
||||||
|
queue linear.NodeQueue
|
||||||
|
visited set.Int64s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk performs a breadth-first traversal of the graph g starting from the given node,
|
||||||
|
// depending on the the EdgeFilter field and the until parameter if they are non-nil. The
|
||||||
|
// traversal follows edges for which EdgeFilter(edge) is true and returns the first node
|
||||||
|
// for which until(node, depth) is true. During the traversal, if the Visit field is
|
||||||
|
// non-nil, it is called with the nodes joined by each followed edge.
|
||||||
|
func (b *BreadthFirst) Walk(g Graph, from graph.Node, until func(n graph.Node, d int) bool) graph.Node {
|
||||||
|
if b.visited == nil {
|
||||||
|
b.visited = make(set.Int64s)
|
||||||
|
}
|
||||||
|
b.queue.Enqueue(from)
|
||||||
|
b.visited.Add(from.ID())
|
||||||
|
|
||||||
|
var (
|
||||||
|
depth int
|
||||||
|
children int
|
||||||
|
untilNext = 1
|
||||||
|
)
|
||||||
|
for b.queue.Len() > 0 {
|
||||||
|
t := b.queue.Dequeue()
|
||||||
|
if until != nil && until(t, depth) {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
tid := t.ID()
|
||||||
|
for _, n := range g.From(tid) {
|
||||||
|
nid := n.ID()
|
||||||
|
if b.EdgeFilter != nil && !b.EdgeFilter(g.Edge(tid, nid)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if b.visited.Has(nid) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if b.Visit != nil {
|
||||||
|
b.Visit(t, n)
|
||||||
|
}
|
||||||
|
b.visited.Add(nid)
|
||||||
|
children++
|
||||||
|
b.queue.Enqueue(n)
|
||||||
|
}
|
||||||
|
if untilNext--; untilNext == 0 {
|
||||||
|
depth++
|
||||||
|
untilNext = children
|
||||||
|
children = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WalkAll calls Walk for each unvisited node of the graph g using edges independent
|
||||||
|
// of their direction. The functions before and after are called prior to commencing
|
||||||
|
// and after completing each walk if they are non-nil respectively. The function
|
||||||
|
// during is called on each node as it is traversed.
|
||||||
|
func (b *BreadthFirst) WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) {
|
||||||
|
b.Reset()
|
||||||
|
for _, from := range g.Nodes() {
|
||||||
|
if b.Visited(from) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if before != nil {
|
||||||
|
before()
|
||||||
|
}
|
||||||
|
b.Walk(g, from, func(n graph.Node, _ int) bool {
|
||||||
|
if during != nil {
|
||||||
|
during(n)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
if after != nil {
|
||||||
|
after()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visited returned whether the node n was visited during a traverse.
|
||||||
|
func (b *BreadthFirst) Visited(n graph.Node) bool {
|
||||||
|
return b.visited.Has(n.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset resets the state of the traverser for reuse.
|
||||||
|
func (b *BreadthFirst) Reset() {
|
||||||
|
b.queue.Reset()
|
||||||
|
b.visited = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DepthFirst implements stateful depth-first graph traversal.
|
||||||
|
type DepthFirst struct {
|
||||||
|
EdgeFilter func(graph.Edge) bool
|
||||||
|
Visit func(u, v graph.Node)
|
||||||
|
stack linear.NodeStack
|
||||||
|
visited set.Int64s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk performs a depth-first traversal of the graph g starting from the given node,
|
||||||
|
// depending on the the EdgeFilter field and the until parameter if they are non-nil. The
|
||||||
|
// traversal follows edges for which EdgeFilter(edge) is true and returns the first node
|
||||||
|
// for which until(node) is true. During the traversal, if the Visit field is non-nil, it
|
||||||
|
// is called with the nodes joined by each followed edge.
|
||||||
|
func (d *DepthFirst) Walk(g Graph, from graph.Node, until func(graph.Node) bool) graph.Node {
|
||||||
|
if d.visited == nil {
|
||||||
|
d.visited = make(set.Int64s)
|
||||||
|
}
|
||||||
|
d.stack.Push(from)
|
||||||
|
d.visited.Add(from.ID())
|
||||||
|
|
||||||
|
for d.stack.Len() > 0 {
|
||||||
|
t := d.stack.Pop()
|
||||||
|
if until != nil && until(t) {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
tid := t.ID()
|
||||||
|
for _, n := range g.From(tid) {
|
||||||
|
nid := n.ID()
|
||||||
|
if d.EdgeFilter != nil && !d.EdgeFilter(g.Edge(tid, nid)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if d.visited.Has(nid) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if d.Visit != nil {
|
||||||
|
d.Visit(t, n)
|
||||||
|
}
|
||||||
|
d.visited.Add(nid)
|
||||||
|
d.stack.Push(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WalkAll calls Walk for each unvisited node of the graph g using edges independent
|
||||||
|
// of their direction. The functions before and after are called prior to commencing
|
||||||
|
// and after completing each walk if they are non-nil respectively. The function
|
||||||
|
// during is called on each node as it is traversed.
|
||||||
|
func (d *DepthFirst) WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) {
|
||||||
|
d.Reset()
|
||||||
|
for _, from := range g.Nodes() {
|
||||||
|
if d.Visited(from) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if before != nil {
|
||||||
|
before()
|
||||||
|
}
|
||||||
|
d.Walk(g, from, func(n graph.Node) bool {
|
||||||
|
if during != nil {
|
||||||
|
during(n)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
if after != nil {
|
||||||
|
after()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visited returned whether the node n was visited during a traverse.
|
||||||
|
func (d *DepthFirst) Visited(n graph.Node) bool {
|
||||||
|
return d.visited.Has(n.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset resets the state of the traverser for reuse.
|
||||||
|
func (d *DepthFirst) Reset() {
|
||||||
|
d.stack = d.stack[:0]
|
||||||
|
d.visited = nil
|
||||||
|
}
|
Loading…
Reference in New Issue