mirror of
https://github.com/ko-build/ko.git
synced 2025-02-07 19:30:23 +02:00
Remove --watch mode (#585)
This commit is contained in:
parent
967e3ebb2d
commit
cd41b3e714
@ -83,7 +83,6 @@ ko apply -f FILENAME [flags]
|
||||
--token string Bearer token for authentication to the API server (DEPRECATED)
|
||||
--user string The name of the kubeconfig user to use (DEPRECATED)
|
||||
--username string Username for basic authentication to the API server (DEPRECATED)
|
||||
-W, --watch Continuously monitor the transitive dependencies of the passed yaml files, and redeploy whenever anything changes. (DEPRECATED)
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
@ -83,7 +83,6 @@ ko create -f FILENAME [flags]
|
||||
--token string Bearer token for authentication to the API server (DEPRECATED)
|
||||
--user string The name of the kubeconfig user to use (DEPRECATED)
|
||||
--username string Username for basic authentication to the API server (DEPRECATED)
|
||||
-W, --watch Continuously monitor the transitive dependencies of the passed yaml files, and redeploy whenever anything changes. (DEPRECATED)
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
@ -58,7 +58,6 @@ ko resolve -f FILENAME [flags]
|
||||
--tag-only Include tags but not digests in resolved image references. Useful when digests are not preserved when images are repopulated.
|
||||
-t, --tags strings Which tags to use for the produced image instead of the default 'latest' tag (may not work properly with --base-import-paths or --bare). (default [latest])
|
||||
--tarball string File to save images tarballs
|
||||
-W, --watch Continuously monitor the transitive dependencies of the passed yaml files, and redeploy whenever anything changes. (DEPRECATED)
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
2
go.mod
2
go.mod
@ -11,11 +11,9 @@ require (
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.11.1
|
||||
github.com/docker/docker v20.10.12+incompatible
|
||||
github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960
|
||||
github.com/fsnotify/fsnotify v1.5.1
|
||||
github.com/go-training/helloworld v0.0.0-20200225145412-ba5f4379d78b
|
||||
github.com/google/go-cmp v0.5.7
|
||||
github.com/google/go-containerregistry v0.8.1-0.20220209165246-a44adc326839
|
||||
github.com/mattmoor/dep-notify v0.0.0-20190205035814-a45dec370a17
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198
|
||||
github.com/sigstore/cosign v1.3.2-0.20211120003522-90e2dcfe7b92
|
||||
github.com/spf13/cobra v1.3.0
|
||||
|
2
go.sum
2
go.sum
@ -1310,8 +1310,6 @@ github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kN
|
||||
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
|
||||
github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
|
||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/mattmoor/dep-notify v0.0.0-20190205035814-a45dec370a17 h1:P91eDVgVzvF2EmA6fmGCyR2VQFlmo2nsmS2DbHoGAco=
|
||||
github.com/mattmoor/dep-notify v0.0.0-20190205035814-a45dec370a17/go.mod h1:qWnF4u+oS4UWOZMwZcBQXrt5IQIdWc6XVJLDdxGIfdQ=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
|
@ -19,25 +19,13 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const deprecation412 = `NOTICE!
|
||||
-----------------------------------------------------------------
|
||||
Watch mode is deprecated and unsupported, and will be removed in
|
||||
a future release.
|
||||
|
||||
For more information see:
|
||||
https://github.com/google/ko/issues/412
|
||||
-----------------------------------------------------------------
|
||||
`
|
||||
|
||||
// FilenameOptions is from pkg/kubectl.
|
||||
type FilenameOptions struct {
|
||||
Filenames []string
|
||||
Recursive bool
|
||||
Watch bool
|
||||
}
|
||||
|
||||
func AddFileArg(cmd *cobra.Command, fo *FilenameOptions) {
|
||||
@ -46,8 +34,6 @@ func AddFileArg(cmd *cobra.Command, fo *FilenameOptions) {
|
||||
"Filename, directory, or URL to files to use to create the resource")
|
||||
cmd.Flags().BoolVarP(&fo.Recursive, "recursive", "R", fo.Recursive,
|
||||
"Process the directory used in -f, --filename recursively. Useful when you want to manage related manifests organized within the same directory.")
|
||||
cmd.Flags().BoolVarP(&fo.Watch, "watch", "W", fo.Watch,
|
||||
"Continuously monitor the transitive dependencies of the passed yaml files, and redeploy whenever anything changes. (DEPRECATED)")
|
||||
}
|
||||
|
||||
// Based heavily on pkg/kubectl
|
||||
@ -56,19 +42,6 @@ func EnumerateFiles(fo *FilenameOptions) chan string {
|
||||
go func() {
|
||||
// When we're done enumerating files, close the channel
|
||||
defer close(files)
|
||||
// When we are in --watch mode, we set up watches on the filesystem locations
|
||||
// that we are supplied and continuously stream files, until we are sent an
|
||||
// interrupt.
|
||||
var watcher *fsnotify.Watcher
|
||||
if fo.Watch {
|
||||
log.Print(deprecation412)
|
||||
var err error
|
||||
watcher, err = fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Fatalf("Unexpected error initializing fsnotify: %v", err)
|
||||
}
|
||||
defer watcher.Close()
|
||||
}
|
||||
for _, paths := range fo.Filenames {
|
||||
// Just pass through '-' as it is indicative of stdin.
|
||||
if paths == "-" {
|
||||
@ -90,9 +63,6 @@ func EnumerateFiles(fo *FilenameOptions) chan string {
|
||||
if path != paths && !fo.Recursive {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if watcher != nil {
|
||||
watcher.Add(path)
|
||||
}
|
||||
// We don't stream back directories, we just decide to skip them, or not.
|
||||
return nil
|
||||
}
|
||||
@ -105,14 +75,6 @@ func EnumerateFiles(fo *FilenameOptions) chan string {
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
// We weren't passed this explicitly, so elide the watch as we
|
||||
// are already watching the directory.
|
||||
} else {
|
||||
// We were passed this directly, and so we may not be watching the
|
||||
// directory, so watch this file explicitly.
|
||||
if watcher != nil {
|
||||
watcher.Add(path)
|
||||
}
|
||||
}
|
||||
|
||||
files <- path
|
||||
@ -122,23 +84,6 @@ func EnumerateFiles(fo *FilenameOptions) chan string {
|
||||
log.Fatalf("Error enumerating files: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// We're done watching the files we were passed and setting up watches.
|
||||
// Now listen for change events from the watches we set up and resend
|
||||
// files that change as if we just saw them (so they can be reprocessed).
|
||||
if watcher != nil {
|
||||
for {
|
||||
select {
|
||||
case event := <-watcher.Events:
|
||||
switch filepath.Ext(event.Name) {
|
||||
case ".json", ".yaml":
|
||||
files <- event.Name
|
||||
}
|
||||
case err := <-watcher.Errors:
|
||||
log.Fatalf("Error watching: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
return files
|
||||
}
|
||||
|
@ -23,14 +23,12 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/mattmoor/dep-notify/pkg/graph"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"gopkg.in/yaml.v3"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
@ -150,9 +148,6 @@ func makeBuilder(ctx context.Context, bo *options.BuildOptions) (*build.Caching,
|
||||
// - if a valid Build future exists at the time of the request,
|
||||
// then block on it.
|
||||
// - if it does not, then initiate and record a Build future.
|
||||
// - When import paths are "affected" by filesystem changes during a
|
||||
// Watch, then invalidate their build futures *before* we put the
|
||||
// affected yaml files onto the channel
|
||||
//
|
||||
// This will benefit the following key cases:
|
||||
// 1. When the same import path is referenced across multiple yaml files
|
||||
@ -295,38 +290,6 @@ func resolveFilesToWriter(
|
||||
// This tracks filename -> []importpath
|
||||
var sm sync.Map
|
||||
|
||||
var g graph.Interface
|
||||
var errCh chan error
|
||||
var err error
|
||||
if fo.Watch {
|
||||
// Start a dep-notify process that on notifications scans the
|
||||
// file-to-recorded-build map and for each affected file resends
|
||||
// the filename along the channel.
|
||||
g, errCh, err = graph.New(func(ss graph.StringSet) {
|
||||
sm.Range(func(k, v interface{}) bool {
|
||||
key := k.(string)
|
||||
value := v.([]string)
|
||||
|
||||
for _, ip := range value {
|
||||
// dep-notify doesn't understand the ko:// prefix
|
||||
ip := strings.TrimPrefix(ip, build.StrictScheme)
|
||||
if ss.Has(ip) {
|
||||
// See the comment above about how "builder" works.
|
||||
// Always use ko:// for the builder.
|
||||
builder.Invalidate(build.StrictScheme + ip)
|
||||
fs <- key
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating dep-notify graph: %w", err)
|
||||
}
|
||||
// Cleanup the fsnotify hooks when we're done.
|
||||
defer g.Shutdown()
|
||||
}
|
||||
|
||||
// This tracks resolution errors and ensures we cancel other builds if an
|
||||
// individual build fails.
|
||||
errs, ctx := errgroup.WithContext(ctx)
|
||||
@ -376,33 +339,11 @@ func resolveFilesToWriter(
|
||||
if err != nil {
|
||||
// This error is sometimes expected during watch mode, so this
|
||||
// isn't fatal. Just print it and keep the watch open.
|
||||
err := fmt.Errorf("error processing import paths in %q: %w", f, err)
|
||||
if fo.Watch {
|
||||
log.Print(err)
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
return fmt.Errorf("error processing import paths in %q: %w", f, err)
|
||||
}
|
||||
// Associate with this file the collection of binary import paths.
|
||||
sm.Store(f, recordingBuilder.ImportPaths)
|
||||
ch <- b
|
||||
if fo.Watch {
|
||||
for _, ip := range recordingBuilder.ImportPaths {
|
||||
// dep-notify doesn't understand the ko:// prefix
|
||||
ip := strings.TrimPrefix(ip, build.StrictScheme)
|
||||
|
||||
// Technically we never remove binary targets from the graph,
|
||||
// which will increase our graph's watch load, but the
|
||||
// notifications that they change will result in no affected
|
||||
// yamls, and no new builds or deploys.
|
||||
if err := g.Add(ip); err != nil {
|
||||
// If we're in watch mode, just fail.
|
||||
err := fmt.Errorf("adding importpath %q to dep graph: %w", ip, err)
|
||||
errCh <- err
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
@ -418,9 +359,6 @@ func resolveFilesToWriter(
|
||||
// be applied.
|
||||
out.Write(append(b, []byte("\n---\n")...))
|
||||
}
|
||||
|
||||
case err := <-errCh:
|
||||
return fmt.Errorf("watching dependencies: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
201
vendor/github.com/mattmoor/dep-notify/LICENSE
generated
vendored
201
vendor/github.com/mattmoor/dep-notify/LICENSE
generated
vendored
@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
19
vendor/github.com/mattmoor/dep-notify/pkg/graph/doc.go
generated
vendored
19
vendor/github.com/mattmoor/dep-notify/pkg/graph/doc.go
generated
vendored
@ -1,19 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 Matt Moore
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package graph holds the utilities for building/maintaining the dependency
|
||||
// graph and notifying on changes.
|
||||
package graph
|
31
vendor/github.com/mattmoor/dep-notify/pkg/graph/interface.go
generated
vendored
31
vendor/github.com/mattmoor/dep-notify/pkg/graph/interface.go
generated
vendored
@ -1,31 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 Matt Moore
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package graph
|
||||
|
||||
// Interface for manipulating the dependency graph.
|
||||
type Interface interface {
|
||||
// This adds a given importpath to the collection of roots that we are tracking.
|
||||
Add(importpath string) error
|
||||
|
||||
// Shutdown stops tracking all Add'ed import paths for changes.
|
||||
Shutdown() error
|
||||
}
|
||||
|
||||
// Observer is the type for the callback that will happen on changes.
|
||||
// The callback is supplied with the transitive dependents (aka "affected
|
||||
// targets") of the file that has changed.
|
||||
type Observer func(affected StringSet)
|
343
vendor/github.com/mattmoor/dep-notify/pkg/graph/manager.go
generated
vendored
343
vendor/github.com/mattmoor/dep-notify/pkg/graph/manager.go
generated
vendored
@ -1,343 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 Matt Moore
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package graph
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
gb "go/build"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
)
|
||||
|
||||
// New creates a new Interface for building up dependency graphs.
|
||||
// It starts in the provided working directory, and will call the provided
|
||||
// Observer for any changes.
|
||||
//
|
||||
// The returned graph is empty, but new targets may be added via the returned
|
||||
// Interface. New also returns any immediate errors, and a channel through which
|
||||
// errors watching for changes in the dependencies will be returned until the
|
||||
// graph is Shutdown.
|
||||
// // Create our empty graph
|
||||
// g, errCh, err := New(...)
|
||||
// if err != nil { ... }
|
||||
// // Cleanup when we're done. This closes errCh.
|
||||
// defer g.Shutdown()
|
||||
// // Start tracking this target.
|
||||
// err := g.Add("github.com/mattmoor/warm-image/cmd/controller")
|
||||
// if err != nil { ... }
|
||||
// select {
|
||||
// case err := <- errCh:
|
||||
// // Handle errors that occur while watching the above target.
|
||||
// case <-stopCh:
|
||||
// // When some stop signal happens, we're done.
|
||||
// }
|
||||
func New(obs Observer) (Interface, chan error, error) {
|
||||
return NewWithOptions(obs, DefaultOptions...)
|
||||
}
|
||||
|
||||
var DefaultOptions = []Option{WithCurrentDirectory, WithContext(&gb.Default), WithFSNotify,
|
||||
WithFileFilter(OmitTest, OmitNonGo), WithPackageFilter(OmitVendor), WithOutsideWorkDirFilter}
|
||||
|
||||
func NewWithOptions(obs Observer, opts ...Option) (Interface, chan error, error) {
|
||||
m := &manager{
|
||||
packages: make(map[string]*node),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
if err := opt(m); err != nil {
|
||||
if m.watcher != nil {
|
||||
m.watcher.Close()
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Start listening for events via the filesystem watcher.
|
||||
go func() {
|
||||
for {
|
||||
event, ok := <-m.eventCh
|
||||
if !ok {
|
||||
// When the channel has been closed, the watcher is shutting down
|
||||
// and we should return to cleanup the go routine.
|
||||
return
|
||||
}
|
||||
|
||||
// Apply our file filters to improve the signal-to-noise.
|
||||
skip := false
|
||||
for _, f := range m.fileFilters {
|
||||
if f(event.Name) {
|
||||
skip = true
|
||||
}
|
||||
}
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
|
||||
// Determine what package contains this file
|
||||
// and signal the change. Call our Observer
|
||||
// on affected targets when we're done.
|
||||
if n := m.enclosingPackage(event.Name); n != nil {
|
||||
m.onChange(n, func(n *node) {
|
||||
obs(m.affectedTargets(n))
|
||||
})
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return m, m.errCh, nil
|
||||
}
|
||||
|
||||
// notification is a callback that internal consumers of manager may use to get
|
||||
// a crack at a node after it has been updated.
|
||||
type notification func(*node)
|
||||
|
||||
// empty implements notification and does nothing.
|
||||
func empty(n *node) {}
|
||||
|
||||
type watcher interface {
|
||||
Add(string) error
|
||||
Remove(string) error
|
||||
Close() error
|
||||
}
|
||||
|
||||
type manager struct {
|
||||
m sync.Mutex
|
||||
|
||||
ctx *gb.Context
|
||||
|
||||
pkgFilters []PackageFilter
|
||||
fileFilters []FileFilter
|
||||
|
||||
packages map[string]*node
|
||||
watcher watcher
|
||||
|
||||
// The working directory relative to which import paths are evaluated.
|
||||
workdir string
|
||||
|
||||
errCh chan error
|
||||
eventCh chan fsnotify.Event
|
||||
}
|
||||
|
||||
// manager implements Interface
|
||||
var _ Interface = (*manager)(nil)
|
||||
|
||||
// manager implements fmt.Stringer
|
||||
var _ fmt.Stringer = (*manager)(nil)
|
||||
|
||||
// Add implements Interface
|
||||
func (m *manager) Add(importpath string) error {
|
||||
m.m.Lock()
|
||||
defer m.m.Unlock()
|
||||
|
||||
_, _, err := m.add(importpath, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// add adds the provided importpath (if it doesn't exist) and optionally
|
||||
// adds the dependent node (if provided) as a dependent of the target.
|
||||
// This returns the node for the provided importpath, whether the dependency
|
||||
// structure has changed, and any errors that may have occurred adding the node.
|
||||
func (m *manager) add(importpath string, dependent *node) (*node, bool, error) {
|
||||
// INVARIANT m.m must be held to call this.
|
||||
if pkg, ok := m.packages[importpath]; ok {
|
||||
return pkg, pkg.addDependent(dependent), nil
|
||||
}
|
||||
|
||||
// New nodes always start as a simple shell, then we set up the
|
||||
// fsnotify and immediate simulate a change to prompt the package
|
||||
// to load its data. A good analogy would be how the "diff" in
|
||||
// a code review for new files looks like everything being added;
|
||||
// so too does this first simulated change pull in the rest of the
|
||||
// dependency graph.
|
||||
newNode := &node{
|
||||
name: importpath,
|
||||
}
|
||||
m.packages[importpath] = newNode
|
||||
newNode.addDependent(dependent)
|
||||
|
||||
// Load the package once to determine it's filesystem location,
|
||||
// and set up a watch on that location.
|
||||
pkg, err := m.ctx.Import(importpath, m.workdir, gb.ImportComment)
|
||||
if err != nil {
|
||||
newNode.removeDependent(dependent)
|
||||
delete(m.packages, importpath)
|
||||
return nil, false, err
|
||||
}
|
||||
if err := m.watcher.Add(pkg.Dir); err != nil {
|
||||
newNode.removeDependent(dependent)
|
||||
delete(m.packages, importpath)
|
||||
return nil, false, err
|
||||
}
|
||||
newNode.dir = pkg.Dir
|
||||
|
||||
// This is done via go routine so that it can take over the lock.
|
||||
go m.onChange(newNode, empty)
|
||||
|
||||
return newNode, true, nil
|
||||
}
|
||||
|
||||
// affectedTargets returns the set of targets that would be affected by a
|
||||
// change to the target represented by the given node. This set is comprised
|
||||
// of the transitive dependents of the node, including itself.
|
||||
func (m *manager) affectedTargets(n *node) StringSet {
|
||||
m.m.Lock()
|
||||
defer m.m.Unlock()
|
||||
|
||||
return n.transitiveDependents()
|
||||
}
|
||||
|
||||
// enclosingPackage returns the node for the package covering the
|
||||
// watched path.
|
||||
func (m *manager) enclosingPackage(path string) *node {
|
||||
m.m.Lock()
|
||||
defer m.m.Unlock()
|
||||
|
||||
dir := filepath.Dir(path)
|
||||
for _, v := range m.packages {
|
||||
if strings.HasSuffix(dir, v.dir) {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// onChange updates the graph based on the current state of the package
|
||||
// represented by the given node. Once the graph has been updated, the
|
||||
// notification function is called on the node.
|
||||
func (m *manager) onChange(changed *node, not notification) {
|
||||
m.m.Lock()
|
||||
defer m.m.Unlock()
|
||||
|
||||
// Load the package information and update dependencies.
|
||||
pkg, err := m.ctx.Import(changed.name, m.workdir, gb.ImportComment)
|
||||
if err != nil {
|
||||
m.errCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
// haveDepsChanged := false
|
||||
seen := make(StringSet)
|
||||
for _, ip := range pkg.Imports {
|
||||
if ip == "C" {
|
||||
// skip cgo
|
||||
continue
|
||||
}
|
||||
subpkg, err := m.ctx.Import(ip, m.workdir, gb.ImportComment)
|
||||
if err != nil {
|
||||
m.errCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
skip := false
|
||||
for _, f := range m.pkgFilters {
|
||||
if f(subpkg) {
|
||||
skip = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
n, chg, err := m.add(subpkg.ImportPath, changed)
|
||||
if err != nil {
|
||||
m.errCh <- err
|
||||
return
|
||||
} else if chg {
|
||||
// haveDepsChanged = true
|
||||
}
|
||||
if changed.addDependency(n) {
|
||||
// haveDepsChanged = true
|
||||
}
|
||||
seen.Add(subpkg.ImportPath)
|
||||
}
|
||||
|
||||
// Remove dependencies that we no longer have.
|
||||
removed := changed.removeUnseenDependencies(seen)
|
||||
if len(removed) > 0 {
|
||||
// haveDepsChanged = true
|
||||
}
|
||||
for _, dependency := range removed {
|
||||
d := dependency
|
||||
go m.maybeGC(d)
|
||||
}
|
||||
|
||||
// log.Printf("Processing %s, have deps changed: %v", changed.name, haveDepsChanged)
|
||||
// Done via go routine so that we can be passed a callback that
|
||||
// takes the lock on manager.
|
||||
go not(changed)
|
||||
}
|
||||
|
||||
func (m *manager) maybeGC(n *node) {
|
||||
m.m.Lock()
|
||||
defer m.m.Unlock()
|
||||
|
||||
if len(n.dependents) > 0 {
|
||||
// It has dependents, so it should not be removed.
|
||||
return
|
||||
}
|
||||
|
||||
// If it has zero dependents, then remove it from the packages map.
|
||||
delete(m.packages, n.name)
|
||||
|
||||
// Lookup the package information, so that we know what directory to stop watching.
|
||||
subpkg, err := m.ctx.Import(n.name, m.workdir, gb.ImportComment)
|
||||
if err != nil {
|
||||
m.errCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
// Remove the watch on the package's directory
|
||||
if err := m.watcher.Remove(subpkg.Dir); err != nil {
|
||||
m.errCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
for _, dependency := range n.dependencies {
|
||||
dependency.removeDependent(n)
|
||||
|
||||
d := dependency
|
||||
go m.maybeGC(d)
|
||||
}
|
||||
}
|
||||
|
||||
// Shutdown implements Interface.
|
||||
func (m *manager) Shutdown() error {
|
||||
return m.watcher.Close()
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer
|
||||
func (m *manager) String() string {
|
||||
m.m.Lock()
|
||||
defer m.m.Unlock()
|
||||
|
||||
// WTB Topo sort.
|
||||
order := []string{}
|
||||
for k := range m.packages {
|
||||
order = append(order, k)
|
||||
}
|
||||
sort.Strings(order)
|
||||
|
||||
parts := []string{}
|
||||
for _, key := range order {
|
||||
parts = append(parts, m.packages[key].String())
|
||||
}
|
||||
return strings.Join(parts, "\n")
|
||||
}
|
119
vendor/github.com/mattmoor/dep-notify/pkg/graph/manager_options.go
generated
vendored
119
vendor/github.com/mattmoor/dep-notify/pkg/graph/manager_options.go
generated
vendored
@ -1,119 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 Matt Moore
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package graph
|
||||
|
||||
import (
|
||||
gb "go/build"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
)
|
||||
|
||||
// PackageFilter is the type of functions that determine whether to omit a
|
||||
// particular Go package from the dependency graph.
|
||||
type PackageFilter func(*gb.Package) bool
|
||||
|
||||
// OmitVendor implements PackageFilter to exclude packages in the vendor directory.
|
||||
func OmitVendor(pkg *gb.Package) bool {
|
||||
return strings.Contains(pkg.ImportPath, "/vendor/")
|
||||
}
|
||||
|
||||
// FileFilter is the type of functions that determine whether to omit a particular
|
||||
// file from triggering a package-level event.
|
||||
type FileFilter func(string) bool
|
||||
|
||||
// OmitNonGo implements FileFilter to exclude non-Go files from triggering package
|
||||
// change notifications.
|
||||
func OmitNonGo(path string) bool {
|
||||
return filepath.Ext(path) != ".go"
|
||||
}
|
||||
|
||||
// OmitTests implements FileFilter to exclude Go test files from triggering package
|
||||
// change notifications.
|
||||
func OmitTest(path string) bool {
|
||||
return strings.HasSuffix(path, "_test.go")
|
||||
}
|
||||
|
||||
// Option is used to mutate the underlying graph implementation during construction.
|
||||
// Since the implementation's type is private this may only be implemented from within
|
||||
// this package.
|
||||
type Option func(*manager) error
|
||||
|
||||
// WithWorkDir configures the graph to use the provided working directory.
|
||||
func WithWorkDir(workdir string) Option {
|
||||
return func(m *manager) error {
|
||||
m.workdir = workdir
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithCurrentDirectory configures the working directory to be the current directory
|
||||
func WithCurrentDirectory(m *manager) error {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return WithWorkDir(wd)(m)
|
||||
}
|
||||
|
||||
// WithContext configures the graph to use the provided Go build context.
|
||||
func WithContext(ctx *gb.Context) Option {
|
||||
return func(m *manager) error {
|
||||
m.ctx = ctx
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithFSNotify configures the graph to use fsnotify to implement its watcher and error channel.
|
||||
func WithFSNotify(m *manager) error {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.watcher = watcher
|
||||
m.errCh = watcher.Errors
|
||||
m.eventCh = watcher.Events
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithFileFilter configures the graph implementation with the provided file filters.
|
||||
func WithFileFilter(ff ...FileFilter) Option {
|
||||
return func(m *manager) error {
|
||||
m.fileFilters = append(m.fileFilters, ff...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithPackageFilter configures the graph implementation with the provided package filters.
|
||||
func WithPackageFilter(ff ...PackageFilter) Option {
|
||||
return func(m *manager) error {
|
||||
m.pkgFilters = append(m.pkgFilters, ff...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithOutsideWorkDirFilter configures the graph with a package filter that omits files outside
|
||||
// of the configured working directory.
|
||||
func WithOutsideWorkDirFilter(m *manager) error {
|
||||
m.pkgFilters = append(m.pkgFilters, func(pkg *gb.Package) bool {
|
||||
return !strings.HasPrefix(pkg.Dir, m.workdir)
|
||||
})
|
||||
return nil
|
||||
}
|
185
vendor/github.com/mattmoor/dep-notify/pkg/graph/node.go
generated
vendored
185
vendor/github.com/mattmoor/dep-notify/pkg/graph/node.go
generated
vendored
@ -1,185 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 Matt Moore
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package graph
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// node holds a single node in our dependency graph and its immediately adjacent neighbors.
|
||||
type node struct {
|
||||
// The canonical import path for this node.
|
||||
name string
|
||||
|
||||
// The directory from which we pull this import path.
|
||||
dir string
|
||||
|
||||
// The dependency structure
|
||||
dependencies []*node
|
||||
dependents []*node
|
||||
}
|
||||
|
||||
// node implements fmt.Stringer
|
||||
var _ fmt.Stringer = (*node)(nil)
|
||||
|
||||
// String implements fmt.Stringer
|
||||
func (n *node) String() string {
|
||||
return fmt.Sprintf(`---
|
||||
name: %s
|
||||
depdnt: %v
|
||||
depdncy: %v`, n.name, names(n.dependents), names(n.dependencies))
|
||||
}
|
||||
|
||||
// addDependent adds the given dependent to the list of dependents for
|
||||
// the given dependency. Dependent may be nil.
|
||||
// This returns whether the node's neighborhood changes.
|
||||
// The manager's lock must be held before calling this.
|
||||
func (dependency *node) addDependent(dependent *node) bool {
|
||||
if dependent == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, depdnt := range dependency.dependents {
|
||||
if depdnt == dependent {
|
||||
// Already a dependent
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// log.Printf("Adding %s <- %s", dependent.name, dependency.name)
|
||||
dependency.dependents = append(dependency.dependents, dependent)
|
||||
return true
|
||||
}
|
||||
|
||||
// addDependency adds the given dependency to the list of dependencies for
|
||||
// the given dependent. Neither parameter may be nil.
|
||||
// This returns whether the node's neighborhood changes.
|
||||
// The manager's lock must be held before calling this.
|
||||
func (dependent *node) addDependency(dependency *node) bool {
|
||||
for _, depdcy := range dependent.dependencies {
|
||||
if depdcy == dependency {
|
||||
// Already a dependency
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// log.Printf("Adding %s -> %s", dependent.name, dependency.name)
|
||||
dependent.dependencies = append(dependent.dependencies, dependency)
|
||||
return true
|
||||
}
|
||||
|
||||
// removeDependent removes the given dependent to the list of dependents for
|
||||
// the given dependency. Dependent may be nil.
|
||||
// This returns whether the node's neighborhood changes.
|
||||
// The manager's lock must be held before calling this.
|
||||
func (dependency *node) removeDependent(dependent *node) bool {
|
||||
for i, depdnt := range dependency.dependents {
|
||||
if depdnt == dependent {
|
||||
dependency.dependents = append(
|
||||
dependency.dependents[:i], dependency.dependents[i+1:]...)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// removeDependency removes the given dependency to the list of dependencies for
|
||||
// the given dependent. Neither parameter may be nil.
|
||||
// This returns whether the node's neighborhood changes.
|
||||
// The manager's lock must be held before calling this.
|
||||
func (dependent *node) removeDependency(dependency *node) bool {
|
||||
for i, depdcy := range dependent.dependencies {
|
||||
if depdcy == dependency {
|
||||
dependent.dependencies = append(
|
||||
dependent.dependencies[:i], dependent.dependencies[i+1:]...)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// removeUnseenDependencies removes dependencies that aren't in the list of seen
|
||||
// names. Returns the list of nodes that correspond to the named dependencies removed.
|
||||
func (dependent *node) removeUnseenDependencies(seen StringSet) []*node {
|
||||
keep := make([]*node, 0, len(dependent.dependencies))
|
||||
toss := make([]*node, 0, len(dependent.dependencies))
|
||||
for _, dep := range dependent.dependencies {
|
||||
if seen.Has(dep.name) {
|
||||
keep = append(keep, dep)
|
||||
} else {
|
||||
toss = append(toss, dep)
|
||||
dependent.removeDependency(dep)
|
||||
dep.removeDependent(dependent)
|
||||
}
|
||||
}
|
||||
dependent.dependencies = keep
|
||||
return toss
|
||||
}
|
||||
|
||||
// transitiveDependents collects the set of node names transitively reachable
|
||||
// by following the "dependents" edges.
|
||||
func (n *node) transitiveDependents() StringSet {
|
||||
return n.transitiveFoo(func(n *node) []*node {
|
||||
return n.dependents
|
||||
})
|
||||
}
|
||||
|
||||
// transitiveDependencies collects the set of node names transitively reachable
|
||||
// by following the "dependencies" edges.
|
||||
func (n *node) transitiveDependencies() StringSet {
|
||||
return n.transitiveFoo(func(n *node) []*node {
|
||||
return n.dependencies
|
||||
})
|
||||
}
|
||||
|
||||
// neighbors defines a function for returning the neighbors of a
|
||||
// particular node.
|
||||
type neighbors func(*node) []*node
|
||||
|
||||
// transitiveDependents collects the set of node names transitively reachable
|
||||
// by following the edges determines by the "neighbors" function.
|
||||
func (n *node) transitiveFoo(nbr neighbors) StringSet {
|
||||
// We will use "set" as the visited group for our DFS.
|
||||
set := make(StringSet)
|
||||
queue := []*node{n}
|
||||
|
||||
for len(queue) != 0 {
|
||||
// Pop the top element off of the queue.
|
||||
top := queue[len(queue)-1]
|
||||
queue = queue[:len(queue)-1]
|
||||
// Check/Mark visited
|
||||
if set.Has(top.name) {
|
||||
continue
|
||||
}
|
||||
set.Add(top.name)
|
||||
|
||||
// Append this node's dependents to our search.
|
||||
queue = append(queue, nbr(top)...)
|
||||
}
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
// names returns the deduplicated and sorted names of the provided nodes.
|
||||
func names(ns []*node) []string {
|
||||
ss := make(StringSet, len(ns))
|
||||
for _, n := range ns {
|
||||
ss.Add(n.name)
|
||||
}
|
||||
return ss.InOrder()
|
||||
}
|
51
vendor/github.com/mattmoor/dep-notify/pkg/graph/set.go
generated
vendored
51
vendor/github.com/mattmoor/dep-notify/pkg/graph/set.go
generated
vendored
@ -1,51 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 Matt Moore
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package graph
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
// StringSet is a simple abstraction for holding a collection of deduplicated strings.
|
||||
type StringSet map[string]struct{}
|
||||
|
||||
// Add inserts a provided key into our set.
|
||||
func (ss *StringSet) Add(key string) {
|
||||
(*ss)[key] = struct{}{}
|
||||
}
|
||||
|
||||
// Remove deletes a provided key from our set.
|
||||
func (ss *StringSet) Remove(key string) {
|
||||
delete(*ss, key)
|
||||
}
|
||||
|
||||
// Has returns whether the set contains the provided key.
|
||||
func (ss *StringSet) Has(key string) bool {
|
||||
_, ok := (*ss)[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
// InOrder returns the keys of the set in the ordering determined by sort.Strings.
|
||||
func (ss StringSet) InOrder() []string {
|
||||
keys := make([]string, 0, len(ss))
|
||||
for k := range ss {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
return keys
|
||||
}
|
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@ -175,7 +175,6 @@ github.com/evanphx/json-patch/v5
|
||||
# github.com/form3tech-oss/jwt-go v3.2.5+incompatible
|
||||
github.com/form3tech-oss/jwt-go
|
||||
# github.com/fsnotify/fsnotify v1.5.1
|
||||
## explicit
|
||||
github.com/fsnotify/fsnotify
|
||||
# github.com/go-logr/logr v1.2.0
|
||||
github.com/go-logr/logr
|
||||
@ -259,9 +258,6 @@ github.com/klauspost/compress/zstd
|
||||
github.com/klauspost/compress/zstd/internal/xxhash
|
||||
# github.com/magiconair/properties v1.8.5
|
||||
github.com/magiconair/properties
|
||||
# github.com/mattmoor/dep-notify v0.0.0-20190205035814-a45dec370a17
|
||||
## explicit
|
||||
github.com/mattmoor/dep-notify/pkg/graph
|
||||
# github.com/mattn/go-isatty v0.0.14
|
||||
github.com/mattn/go-isatty
|
||||
# github.com/mitchellh/go-homedir v1.1.0
|
||||
|
Loading…
x
Reference in New Issue
Block a user