├── .editorconfig ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.yaml │ ├── config.yaml │ ├── documentation.yaml │ └── proposal.md ├── pull_request_template.md └── workflows │ └── ci.yaml ├── .gitignore ├── .golangci.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── GOVERNANCE.md ├── LICENSE ├── MAINTAINERS.md ├── Makefile ├── README.md ├── ROADMAP.md ├── SECURITY.md ├── cmd ├── github.go ├── patch.go ├── root.go └── scaffold.go ├── go.mod ├── go.sum ├── internal ├── log │ ├── log.go │ ├── symbol.go │ └── wrapper.go ├── option │ └── option.go ├── pkg │ ├── github │ │ └── github.go │ ├── patch │ │ ├── patch.go │ │ └── patch_test.go │ └── scaffold │ │ ├── scaffold.go │ │ ├── scaffold_test.go │ │ └── tree │ │ ├── parse.go │ │ └── tree.go └── response │ └── response.go └── main.go /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | 9 | [*.{go,mod}] 10 | indent_style = tab 11 | 12 | [Makefile] 13 | indent_style = tab 14 | 15 | [*.md] 16 | max_line_length = off 17 | trim_trailing_whitespace = false 18 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | *.{png,jpg,jpeg,gif,webp,woff,woff2} binary 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yaml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Report a bug of DevStream 3 | title: ":bomb: `Bug`: " 4 | labels: bug 5 | body: 6 | - type: textarea 7 | id: problem 8 | attributes: 9 | label: What Happened? 10 | description: Please provide as much information as possible. 11 | validations: 12 | required: true 13 | - type: textarea 14 | id: repro 15 | attributes: 16 | label: How to Reproduce? 17 | validations: 18 | required: false 19 | - type: textarea 20 | id: else 21 | attributes: 22 | label: Anything else 23 | validations: 24 | required: false 25 | - type: dropdown 26 | id: version 27 | attributes: 28 | label: 'DevStream Version' 29 | description: "To find out the version run: `dtm version`" 30 | options: 31 | - < v0.13.0 32 | - v0.13.0 33 | - latest 34 | validations: 35 | required: true 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yaml: -------------------------------------------------------------------------------- 1 | contact_links: 2 | - name: Support 3 | url: https://cloud-native.slack.com/archives/C03LA2B8K0A 4 | about: Support requests or questions related to DevStream 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation.yaml: -------------------------------------------------------------------------------- 1 | name: Documentation Issue 2 | description: Help to improve our documentation 3 | title: ":open_book: `Docs`: " 4 | labels: docs 5 | body: 6 | - type: textarea 7 | id: problem 8 | attributes: 9 | label: What should be changed? 10 | description: Please provide as much info as possible. 11 | validations: 12 | required: true 13 | - type: checkboxes 14 | id: terms 15 | attributes: 16 | label: Please read the documents below. 17 | options: 18 | - label: I've read the document [Creating a Documentation for DevStream](https://docs.devstream.io/en/latest/development/mkdocs/) and [Document Translation(Chinese only)](https://docs.devstream.io/en/latest/development/translation.zh/). (If you want to submit a document type contribution.) 19 | required: false 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/proposal.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Proposal 3 | about: File a Proposal 4 | title: ":four_leaf_clover: `Proposal`: " 5 | labels: proposal 6 | --- 7 | 8 | ## What Would You Like to Add? Why Is This Needed? 9 | 12 | 13 | 14 | 15 | ## Design 16 | 17 | 18 | 19 | ## Anything else 20 | 23 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Pre-Checklist 2 | 3 | Note: please complete **_ALL_** items in the following checklist. 4 | 5 | - [ ] I have read through the [CONTRIBUTING.md](https://github.com/devstream-io/devstream/blob/main/CONTRIBUTING.md) documentation. 6 | - [ ] My code has the necessary comments and documentation (if needed). 7 | - [ ] I have added relevant tests 8 | 9 | ## Description 10 | 13 | 14 | ## Related Issues 15 | 18 | 19 | ## New Behavior (screenshots if needed) 20 | 23 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Set up Go 16 | uses: actions/setup-go@v4 17 | with: 18 | go-version: 1.20 19 | cache: true 20 | 21 | - name: Check out code 22 | uses: actions/checkout@v3 23 | 24 | - name: Run tests 25 | run: go test -v ./... 26 | 27 | - name: Build project 28 | run: make build 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac OS X files 2 | .DS_Store 3 | 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.dll 7 | *.so 8 | *.dylib 9 | 10 | # Build 11 | dtm 12 | 13 | # Test binary, build with `go test -c` 14 | *.test 15 | 16 | # Output of the go coverage tool, specifically when used with LiteIDE 17 | *.out 18 | 19 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 20 | .glide/ 21 | 22 | # IDE 23 | .idea/ 24 | .vscode/ 25 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | # options for analysis running 2 | run: 3 | # timeout for analysis, e.g. 30s, 5m, default is 1m 4 | timeout: 10m 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Conduct 2 | 3 | We are committed to providing a friendly, safe and welcoming environment for all, regardless of the level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristics. 4 | 5 | Please avoid using overtly sexual aliases or other nicknames that might detract from a friendly, safe, and welcoming environment for all. 6 | 7 | Please be kind and courteous. There’s no need to be mean or rude. 8 | 9 | Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. 10 | 11 | Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. 12 | 13 | We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term “harassment” as including the definition in the Citizen Code of Conduct; if you lack clarity about what might be included in that concept, please read their definition. In particular, we don’t tolerate behavior that excludes people in socially marginalized groups. 14 | 15 | Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please get in touch with one of the channel ops or any of the DevStream moderation team immediately. Whether you’re a regular contributor or a newcomer, we care about making this community a safe place for you, and we’ve got your back. 16 | 17 | Any spamming, trolling, flaming, baiting, or other attention-stealing behavior is not welcome. 18 | 19 | [Email The Moderation Team](mailto:tao.hu@merico.dev) 20 | 21 | ## Moderation 22 | 23 | These are the policies for upholding our community’s standards of conduct. If you feel that a thread needs moderation, please get in touch with the DevStream moderation team. 24 | 25 | Remarks that violate the DevStream standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hostile manner.) 26 | 27 | Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. 28 | 29 | Moderators will first respond to such remarks with a warning. 30 | 31 | If the warning is unheeded, the user will be “kicked,” i.e., kicked out of the communication channel to cool off. 32 | 33 | If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. 34 | 35 | Moderators may choose at their discretion to un-ban the user if it was the first offense, and they offer the offended party a genuine apology. 36 | 37 | If a moderator bans someone and you think it was unjustified, please take it up with that moderator or a different moderator in private. Complaints about bans in-channel are not allowed. 38 | 39 | Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. 40 | 41 | In the DevStream community, we strive to go the extra step to look out for each other. Don’t just aim to be technically unimpeachable; try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they’re off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. 42 | 43 | And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could’ve communicated better - remember that it’s your responsibility to make your fellows comfortable. Everyone wants to get along, and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. 44 | 45 | The enforcement policies listed above apply to all official DevStream venues, including Discord channels and GitHub repository. 46 | 47 | The DevStream code of conduct is adapted from the [Rust code of conduct](https://www.rust-lang.org/policies/code-of-conduct). 48 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Welcome to DevStream! 4 | 5 | Thanks for contributing, and thanks for reading this doc before doing it! 6 | 7 | The [DevStream Docs website](https://docs.devstream.io) contains information about how to get started, how the community organizes, and more. See the followings for more details before you decide to contribute: 8 | 9 | - [Contributing Guide](https://docs.devstream.io/en/latest/contributing_guide/). 10 | - [Development Workflow](https://docs.devstream.io/en/latest/development/git-workflow/git-workflow/), and other docs under the "Developer Guide" section. 11 | 12 | Those guidelines, as the name suggests, are only guidelines, not rules. So, use your best judgment, and feel free to propose changes to the contribute/development docs. 13 | -------------------------------------------------------------------------------- /GOVERNANCE.md: -------------------------------------------------------------------------------- 1 | # Project Governance 2 | 3 | ## Values 4 | 5 | DevStream and its leadership embrace the following values: 6 | 7 | - Inclusivity: We innovate through different perspectives and skill sets, which can only be accomplished in a welcoming and respectful environment. 8 | 9 | - Insist on the Highest Standards: Contributors have relentlessly high standards — many people may think these standards are unreasonably high. Contributors are continually raising the bar and drive their teams to deliver high quality products, services, and processes. Contributors ensure that defects do not get sent down the line and that problems are fixed so they stay fixed. 10 | 11 | - Ownership: Contributors are owners. They think long term and don’t sacrifice long-term value for short-term results. They act on behalf of the entire community, beyond just their own. They never say "that’s not my job." 12 | 13 | - Participation: Responsibilities within the project are earned through participation, and there is a clear path up the contributor ladder into leadership positions. 14 | 15 | - Community over Product or Company: Sustaining and growing our community takes priority over shipping code or sponsors' organizational goals. Each contributor participates in the project as an individual. 16 | 17 | - Openness: Communication and decision-making happen in the open and is discoverable for future reference as much as possible. All discussions and work take place in public Slack channels and open repositories. 18 | 19 | - Fairness: All stakeholders have the opportunity to provide feedback and submit contributions, which will be considered on their merits. 20 | 21 | ## Maintainers 22 | 23 | DevStream Maintainers have write access to the [DevStream GitHub repository](https://github.com/devstream-io/devstream). They can merge their patches or patches from others. The current maintainers can be found in [CODEOWNERS](./CODEOWNERS). Maintainers collectively manage the project's resources and contributors. 24 | 25 | This privilege is granted with some expectation of responsibility: maintainers are people who care about the DevStream project and want to help it grow and improve. A maintainer is not just someone who can make changes, but someone who has demonstrated their ability to collaborate with the team, get the most knowledgeable people to review code and docs, contribute high-quality code, and follow through to fix issues (in code or tests). 26 | 27 | A maintainer is a contributor to the project's success and a citizen helping the project succeed. 28 | 29 | ## Becoming a Maintainer 30 | 31 | See [here](https://docs.devstream.io/en/latest/contributor_ladder/#maintainer). 32 | 33 | ## Meetings 34 | 35 | Time zones permitting, Maintainers are expected to participate in the public developer meeting, which is published [here](https://github.com/devstream-io/devstream/wiki). 36 | 37 | Maintainers will also have closed meetings to discuss security reports or Code of Conduct violations. Such meetings should be scheduled by any Maintainer on receipt of a security issue or CoC report. All current Maintainers must be invited to such closed meetings, except for any Maintainer who is accused of a CoC violation. 38 | 39 | ## CNCF Resources 40 | 41 | Any Maintainer may suggest a request for CNCF resources during a meeting. A simple majority of Maintainers approve the request. The Maintainers may also choose to delegate working with the CNCF to non-Maintainer community members. 42 | 43 | ## Code of Conduct 44 | 45 | [Code of Conduct](./CODE_OF_CONDUCT.md) violations by community members will be discussed and resolved during the private maintainer meeting. If the reported CoC violator is a Maintainer, the Maintainers will instead designate two Maintainers to work with CNCF staff in resolving the report. 46 | 47 | ## Voting 48 | 49 | While most business in DevStream is conducted by "lazy consensus", periodically the Maintainers may need to vote on specific actions or changes. A vote can be taken during a community meeting or a private maintainer meeting for security or conduct matters. Any Maintainer may 50 | demand a vote be taken. 51 | 52 | Most votes require a simple majority of all Maintainers to succeed. Maintainers can be removed by a 2/3 majority vote of all Maintainers, and changes to this Governance require a 2/3 vote of all Maintainers. 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | # Current DevStream Project Maintainers 2 | 3 | Please keep the list sorted alphabetically by GitHub handle. 4 | 5 | | Github ID | Name | Email | 6 | |---------------------------------------------------|------------------------|------------------------------------| 7 | | [@daniel-hutao](https://github.com/daniel-hutao/) | Daniel Hu | tao.hu@merico.dev | 8 | 9 | 10 | ### Previous Project Maintainers: 11 | 12 | | Github ID | Name | 13 | |---------------------------------------------------|------------------------| 14 | | [@IronCore864](https://github.com/IronCore864/) | Tiexin Guo | 15 | | [@lfbdev](https://github.com/lfbdev) | Fangbao Li | 16 | | [@aFlyBird0](https://github.com/aFlyBird0) | Hepeng Li | 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DTM_ROOT=github.com/devstream-io/devstream 2 | SELF_DIR=$(dir $(lastword $(MAKEFILE_LIST))) 3 | GOOS=$(shell go env GOOS) 4 | GOPATH=$(shell go env GOPATH) 5 | GOARCH=$(shell go env GOARCH) 6 | 7 | 8 | # COLORS 9 | RED = $(shell printf "\33[31m") 10 | GREEN = $(shell printf "\33[32m") 11 | WHITE = $(shell printf "\33[37m") 12 | YELLOW = $(shell printf "\33[33m") 13 | RESET = $(shell printf "\33[0m") 14 | 15 | ifeq ($(origin ROOT_DIR),undefined) 16 | ROOT_DIR := $(abspath $(shell cd $(SELF_DIR) && pwd -P)) 17 | endif 18 | 19 | FIND := find . -path './cmd/*.go' -o -path './internal/pkg/*.go' 20 | 21 | .PHONY: build 22 | build: fmt vet mod-tidy ## Build dtm core only, without plugins, locally. 23 | go build -trimpath -o dtm . 24 | @echo "${GREEN}✔'dtm' has been generated in the current directory($(PWD))!${RESET}" 25 | 26 | .PHONY: fmt 27 | fmt: verify.goimports ## Run 'go fmt' & goimports against code. 28 | @echo "$(YELLOW)Formating codes$(RESET)" 29 | @$(FIND) -type f | xargs gofmt -s -w 30 | @$(FIND) -type f | xargs ${GOPATH}/bin/goimports -w -local $(DTM_ROOT) 31 | @go mod edit -fmt 32 | 33 | #.PHONY: lint 34 | #lint: verify.golangcilint ## Run 'golangci-lint' against code. 35 | # @echo "$(YELLOW)Run golangci to lint source codes$(RESET)" 36 | # @${GOPATH}/bin/golangci-lint -c $(ROOT_DIR)/.golangci.yml run $(ROOT_DIR)/... 37 | 38 | .PHONY: vet 39 | vet: ## Run "go vet ./...". 40 | go vet ./... 41 | 42 | .PHONY: mod-tidy 43 | mod-tidy: ## Run "go mod tidy". 44 | go mod tidy 45 | 46 | .PHONY: verify.% 47 | verify.%: 48 | @if ! command -v $* >/dev/null 2>&1; then $(MAKE) install.$*; fi 49 | 50 | .PHONY: install.goimports 51 | install.goimports: 52 | @go install golang.org/x/tools/cmd/goimports@latest 53 | 54 | .PHONY: install.golangcilint 55 | install.golangcilint: 56 | @go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DevStream 2 | 3 | to be updated 4 | -------------------------------------------------------------------------------- /ROADMAP.md: -------------------------------------------------------------------------------- 1 | todo 2 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # DevStream Security Policy 2 | 3 | Version: **v0.12 (2023-04-24)** 4 | 5 | ## Overview 6 | 7 | As a tool manager, some of the tools need to be installed in a production environment. Thus, some of DevStream's plugins need to have production access, which makes security an important topic. 8 | 9 | The DevStream team takes security as job zero and improves it continuously. 10 | 11 | ## Supported Versions 12 | 13 | We currently support the most recent release (`N`, e.g. `0.2`) and the release previous to the most recent one (`N-1`, e.g. `0.1`). With the release of `N+1`, `N-1` drops out of support and `N` becomes `N-1`. 14 | 15 | We regularly perform patch releases (e.g. `0.1.1` and `0.2.1`) for supported versions, which will contain fixes for security vulnerabilities. Prior releases might receive critical security fixes on a best effort basis, however, it cannot be guaranteed that security fixes get back-ported to these unsupported versions. 16 | 17 | In some cases, where a security fix needs complex re-design of a feature or is otherwise very intrusive, and there's a workaround available, we may decide to provide a forward-fix only, e.g. to be released the next minor release, instead of releasing it within a patch branch for the currently supported releases. 18 | 19 | ## Reporting a Vulnerability 20 | 21 | Please report vulnerabilities by e-mail to the following address: 22 | 23 | - tao.hu@merico.dev 24 | 25 | If you find a security-related bug in DevStream, we kindly ask you to disclose responsibly and give us appropriate time to react to mitigate the vulnerability. 26 | 27 | We do our best to react quickly. Sometimes, it might take a little longer (e.g. out-of-office conditions); please bear with us in these cases. 28 | 29 | We publish security advisories using the [Git Hub Security Advisories](https://github.com/devstream-io/devstream/security/advisories) feature to keep our community well informed, and will credit you for your 30 | findings (unless you prefer to stay anonymous, of course). 31 | -------------------------------------------------------------------------------- /cmd/github.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | 6 | "github.com/devstream-io/devstream/internal/pkg/github" 7 | ) 8 | 9 | // githubCmd represents the github command 10 | var githubCmd = &cobra.Command{ 11 | Use: "github", 12 | Short: "github is used to execute github operations", 13 | Long: `github is used to execute github operations 14 | 参考 gh`, 15 | Run: func(cmd *cobra.Command, args []string) { 16 | github.Run() 17 | }, 18 | } 19 | 20 | func init() { 21 | rootCmd.AddCommand(githubCmd) 22 | } 23 | -------------------------------------------------------------------------------- /cmd/patch.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2023 NAME HERE 3 | */ 4 | package cmd 5 | 6 | import ( 7 | "os" 8 | 9 | "github.com/devstream-io/devstream/internal/response" 10 | 11 | "github.com/devstream-io/devstream/internal/log" 12 | "github.com/devstream-io/devstream/internal/pkg/patch" 13 | 14 | "github.com/spf13/cobra" 15 | ) 16 | 17 | // patchCmd represents the patch command 18 | var patchCmd = &cobra.Command{ 19 | Use: "patch", 20 | Short: "apply a diff file to an original", 21 | Long: `patch will take a patch file containing any of the four forms of difference listing 22 | produced by the diff program and apply those differences to an original file, 23 | producing a patched version. If patchfile is omitted, or is a hyphen, 24 | the patch will be read from the standard input. 25 | 26 | e.g. 27 | - dtm patch file.patch 28 | - dtm patch file.patch -ojson 29 | `, 30 | Run: func(cmd *cobra.Command, args []string) { 31 | if len(args) != 1 { 32 | log.Error("Incorrect number of arguments") 33 | os.Exit(1) 34 | } 35 | err := patch.Patch(".", args[0]) 36 | if err != nil { 37 | log.Error(err) 38 | r := response.New(response.StatusError, response.MessageError, err.Error()) 39 | r.Print(OutputFormat) 40 | os.Exit(1) 41 | } 42 | r := response.New(response.StatusOK, response.MessageOK, "") 43 | r.Print(OutputFormat) 44 | }, 45 | } 46 | 47 | func init() { 48 | rootCmd.AddCommand(patchCmd) 49 | } 50 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/sirupsen/logrus" 8 | 9 | "github.com/devstream-io/devstream/internal/log" 10 | 11 | "github.com/spf13/cobra" 12 | "github.com/spf13/viper" 13 | 14 | "github.com/devstream-io/devstream/internal/option" 15 | ) 16 | 17 | var cfgFile string 18 | 19 | // isDebug is a flag to enable debug level log 20 | var isDebug bool 21 | 22 | // OutputFormat is the output format for the command. One of: json|yaml|raw 23 | // Default value is "raw" 24 | var OutputFormat string 25 | 26 | // rootCmd represents the base command when called without any subcommands 27 | var rootCmd = &cobra.Command{ 28 | Use: "dtm", 29 | Short: "dtm is a tool to manage variaties of development platforms", 30 | Long: `dtm is a tool to manage variaties of development platforms.`, 31 | PersistentPreRun: func(cmd *cobra.Command, args []string) { 32 | initLog() 33 | }, 34 | } 35 | 36 | // Execute adds all child commands to the root command and sets flags appropriately. 37 | // This is called by main.main(). It only needs to happen once to the rootCmd. 38 | func Execute() { 39 | err := rootCmd.Execute() 40 | if err != nil { 41 | os.Exit(1) 42 | } 43 | } 44 | 45 | func init() { 46 | cobra.OnInitialize(initConfig) 47 | 48 | rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.devstream.yaml)") 49 | rootCmd.PersistentFlags().StringVarP(&OutputFormat, "output", "o", "raw", "Output format. One of: json|yaml|raw") 50 | rootCmd.PersistentFlags().BoolVarP(&isDebug, "debug", "", false, "debug level log") 51 | rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") 52 | } 53 | 54 | // initConfig reads in config file and ENV variables if set. 55 | func initConfig() { 56 | if cfgFile != "" { 57 | // Use config file from the flag. 58 | viper.SetConfigFile(cfgFile) 59 | } else { 60 | // Find home directory. 61 | home, err := os.UserHomeDir() 62 | cobra.CheckErr(err) 63 | 64 | // Search config in home directory with name ".devstream" (without extension). 65 | viper.AddConfigPath(home) 66 | viper.SetConfigType("yaml") 67 | viper.SetConfigName(".devstream") 68 | } 69 | 70 | viper.AutomaticEnv() // read in environment variables that match 71 | 72 | // If a config file is found, read it in. 73 | if err := viper.ReadInConfig(); err == nil { 74 | fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) 75 | } 76 | 77 | if OutputFormat != "raw" { 78 | option.Silence = true 79 | } 80 | } 81 | 82 | func initLog() { 83 | // if OutputFormat is not "raw", set log level to PanicLevel to disable log 84 | if OutputFormat != "raw" { 85 | logrus.SetLevel(logrus.PanicLevel) 86 | } else if isDebug { 87 | logrus.SetLevel(logrus.DebugLevel) 88 | log.Infof("Log level is: %s.", logrus.GetLevel()) 89 | } else { 90 | logrus.SetLevel(logrus.InfoLevel) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /cmd/scaffold.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2023 NAME HERE 3 | */ 4 | package cmd 5 | 6 | import ( 7 | "os" 8 | 9 | "github.com/spf13/cobra" 10 | 11 | "github.com/devstream-io/devstream/internal/log" 12 | "github.com/devstream-io/devstream/internal/pkg/scaffold" 13 | ) 14 | 15 | var structure string 16 | 17 | // scaffoldCmd represents the scaffold command 18 | var scaffoldCmd = &cobra.Command{ 19 | Use: "scaffold", 20 | Short: "scaffold is used to generate folder and file structure", 21 | Long: ` 22 | dtm scaffold " 23 | project/ 24 | ├── src/ 25 | │ ├── main.go 26 | │ └── utils/ 27 | │ ├── file1.go 28 | │ └── file2.go 29 | └── README.md 30 | " 31 | `, 32 | Run: func(cmd *cobra.Command, args []string) { 33 | if len(args) != 1 { 34 | log.Error("Incorrect number of arguments") 35 | os.Exit(1) 36 | } 37 | if err := scaffold.Scaffold(args[0]); err != nil { 38 | log.Error(err) 39 | os.Exit(1) 40 | } 41 | }, 42 | } 43 | 44 | func init() { 45 | rootCmd.AddCommand(scaffoldCmd) 46 | 47 | scaffoldCmd.Flags().StringVarP(&structure, "structure", "s", "", "structure specify the folder and file structure") 48 | } 49 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/devstream-io/devstream 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/onsi/ginkgo v1.16.5 7 | github.com/onsi/gomega v1.27.6 8 | github.com/sirupsen/logrus v1.9.0 9 | github.com/spf13/cobra v1.7.0 10 | github.com/spf13/viper v1.15.0 11 | gopkg.in/gookit/color.v1 v1.1.6 12 | gopkg.in/yaml.v3 v3.0.1 13 | ) 14 | 15 | require ( 16 | github.com/frankban/quicktest v1.14.4 // indirect 17 | github.com/fsnotify/fsnotify v1.6.0 // indirect 18 | github.com/google/go-cmp v0.5.9 // indirect 19 | github.com/hashicorp/hcl v1.0.0 // indirect 20 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 21 | github.com/magiconair/properties v1.8.7 // indirect 22 | github.com/mitchellh/mapstructure v1.5.0 // indirect 23 | github.com/nxadm/tail v1.4.8 // indirect 24 | github.com/pelletier/go-toml/v2 v2.0.6 // indirect 25 | github.com/spf13/afero v1.9.3 // indirect 26 | github.com/spf13/cast v1.5.0 // indirect 27 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 28 | github.com/spf13/pflag v1.0.5 // indirect 29 | github.com/subosito/gotenv v1.4.2 // indirect 30 | golang.org/x/net v0.8.0 // indirect 31 | golang.org/x/sys v0.7.0 // indirect 32 | golang.org/x/text v0.8.0 // indirect 33 | gopkg.in/ini.v1 v1.67.0 // indirect 34 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect 35 | ) 36 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 7 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 8 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 9 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 10 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 11 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 12 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 13 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 14 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 15 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 16 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 17 | cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= 18 | cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= 19 | cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= 20 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 21 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 22 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 23 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 24 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 25 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 26 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 27 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 28 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 29 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 30 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 31 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 32 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 33 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 34 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 35 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 36 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 37 | cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= 38 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 39 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 40 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 41 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 42 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 43 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 44 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 45 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 46 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 47 | github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 48 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 49 | github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 50 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 51 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 52 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 53 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 54 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 55 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 56 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 57 | github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= 58 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 59 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 60 | github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= 61 | github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 62 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 63 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 64 | github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= 65 | github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 66 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 67 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 68 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 69 | github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= 70 | github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 71 | github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= 72 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 73 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 74 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 75 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 76 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 77 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 78 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 79 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 80 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 81 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 82 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 83 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 84 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 85 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 86 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 87 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 88 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 89 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 90 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 91 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 92 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 93 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 94 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 95 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 96 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 97 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= 98 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 99 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 100 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 101 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 102 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 103 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 104 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 105 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 106 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 107 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 108 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 109 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 110 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 111 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 112 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 113 | github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 114 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 115 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 116 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 117 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 118 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 119 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 120 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 121 | github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 122 | github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 123 | github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 124 | github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= 125 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 126 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 127 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 128 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 129 | github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= 130 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 131 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 132 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 133 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 134 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 135 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 136 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 137 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 138 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 139 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 140 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 141 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 142 | github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 143 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 144 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 145 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 146 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 147 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 148 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 149 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 150 | github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= 151 | github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 152 | github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= 153 | github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 154 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 155 | github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= 156 | github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= 157 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 158 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= 159 | github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= 160 | github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= 161 | github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= 162 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 163 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 164 | github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= 165 | github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= 166 | github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= 167 | github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= 168 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 169 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 170 | github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= 171 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 172 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 173 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 174 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 175 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= 176 | github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 177 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 178 | github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= 179 | github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 180 | github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= 181 | github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= 182 | github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= 183 | github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= 184 | github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= 185 | github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= 186 | github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= 187 | github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 188 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 189 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 190 | github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= 191 | github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= 192 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 193 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 194 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 195 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 196 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 197 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 198 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 199 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 200 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 201 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= 202 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 203 | github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= 204 | github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= 205 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 206 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 207 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 208 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 209 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 210 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 211 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 212 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 213 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 214 | go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= 215 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 216 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 217 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 218 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 219 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 220 | golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 221 | golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 222 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 223 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 224 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 225 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 226 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 227 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 228 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 229 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 230 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 231 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 232 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 233 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 234 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 235 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 236 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 237 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 238 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 239 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 240 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 241 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 242 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 243 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 244 | golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 245 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 246 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 247 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 248 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 249 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 250 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 251 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 252 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 253 | golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 254 | golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 255 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 256 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 257 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 258 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 259 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 260 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 261 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 262 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 263 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 264 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 265 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 266 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 267 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 268 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 269 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 270 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 271 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 272 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 273 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 274 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 275 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 276 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 277 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 278 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 279 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 280 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 281 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 282 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 283 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 284 | golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 285 | golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 286 | golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 287 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 288 | golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= 289 | golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= 290 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 291 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 292 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 293 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 294 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 295 | golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 296 | golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 297 | golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 298 | golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 299 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 300 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 301 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 302 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 303 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 304 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 305 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 306 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 307 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 308 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 309 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 310 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 311 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 312 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 313 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 314 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 315 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 316 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 317 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 318 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 319 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 320 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 321 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 322 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 323 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 324 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 325 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 326 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 327 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 328 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 329 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 330 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 331 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 332 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 333 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 334 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 335 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 336 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 337 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 338 | golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 339 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 340 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 341 | golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 342 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 343 | golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 344 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 345 | golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 346 | golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 347 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 348 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 349 | golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 350 | golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= 351 | golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 352 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 353 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 354 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 355 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 356 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 357 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 358 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 359 | golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= 360 | golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 361 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 362 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 363 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 364 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 365 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 366 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 367 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 368 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 369 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 370 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 371 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 372 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 373 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 374 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 375 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 376 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 377 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 378 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 379 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 380 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 381 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 382 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 383 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 384 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 385 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 386 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 387 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 388 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 389 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 390 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 391 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 392 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 393 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 394 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 395 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 396 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 397 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 398 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 399 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 400 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 401 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 402 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 403 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 404 | golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= 405 | golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 406 | golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 407 | golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 408 | golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 409 | golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 410 | golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 411 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 412 | golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= 413 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 414 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 415 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 416 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 417 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 418 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 419 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 420 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 421 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 422 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 423 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 424 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 425 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 426 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 427 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 428 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 429 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 430 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 431 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 432 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 433 | google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= 434 | google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= 435 | google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= 436 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 437 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 438 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 439 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 440 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 441 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 442 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 443 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 444 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 445 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 446 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 447 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 448 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 449 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 450 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 451 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 452 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 453 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 454 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 455 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 456 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 457 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 458 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 459 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 460 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 461 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 462 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 463 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 464 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 465 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 466 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 467 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 468 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 469 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 470 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 471 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 472 | google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 473 | google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 474 | google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 475 | google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 476 | google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 477 | google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 478 | google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 479 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 480 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 481 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 482 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 483 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 484 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 485 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 486 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 487 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 488 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 489 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 490 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 491 | google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 492 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 493 | google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= 494 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 495 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 496 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 497 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 498 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 499 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 500 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 501 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 502 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 503 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 504 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 505 | google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= 506 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 507 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 508 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 509 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 510 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 511 | gopkg.in/gookit/color.v1 v1.1.6 h1:5fB10p6AUFjhd2ayq9JgmJWr9WlTrguFdw3qlYtKNHk= 512 | gopkg.in/gookit/color.v1 v1.1.6/go.mod h1:IcEkFGaveVShJ+j8ew+jwe9epHyGpJ9IrptHmW3laVY= 513 | gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= 514 | gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 515 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 516 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 517 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 518 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 519 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 520 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 521 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 522 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 523 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 524 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 525 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 526 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 527 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 528 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 529 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 530 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 531 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 532 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 533 | -------------------------------------------------------------------------------- /internal/log/log.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "io" 5 | "os" 6 | 7 | "github.com/devstream-io/devstream/internal/option" 8 | "github.com/sirupsen/logrus" 9 | ) 10 | 11 | var ( 12 | debugLog = &CliLoggerFormatter{showType: "debug"} 13 | infoLog = &CliLoggerFormatter{showType: "info"} 14 | warnLog = &CliLoggerFormatter{showType: "warn"} 15 | errorLog = &CliLoggerFormatter{showType: "error"} 16 | fatalLog = &CliLoggerFormatter{showType: "fatal"} 17 | successLog = &CliLoggerFormatter{showType: "success"} 18 | ) 19 | 20 | func RedirectOutput(writer io.Writer) { 21 | logrus.SetOutput(writer) 22 | } 23 | 24 | func RecoverOutput() { 25 | if option.Silence { 26 | return 27 | } 28 | logrus.SetOutput(os.Stdout) 29 | } 30 | 31 | // Debugf log info with color,symbol and format for a notice 32 | func Debugf(format string, args ...interface{}) { 33 | logrus.SetFormatter(debugLog) 34 | logrus.Debugf(format, args...) 35 | } 36 | 37 | // Debug log info with color and symbol, for a notice 38 | func Debug(args ...interface{}) { 39 | logrus.SetFormatter(debugLog) 40 | logrus.Debug(args...) 41 | } 42 | 43 | // Infof log info with color,symbol and format for a notice 44 | func Infof(format string, args ...interface{}) { 45 | logrus.SetFormatter(infoLog) 46 | logrus.Infof(format, args...) 47 | } 48 | 49 | // Info log info with color and symbol, for a notice 50 | func Info(args ...interface{}) { 51 | logrus.SetFormatter(infoLog) 52 | logrus.Info(args...) 53 | } 54 | 55 | // Warnf log warn with color,symbol and format for a warning event 56 | func Warnf(format string, args ...interface{}) { 57 | logrus.SetFormatter(warnLog) 58 | logrus.Warnf(format, args...) 59 | } 60 | 61 | // Warn log warn with color and symbol, for a warning event 62 | func Warn(args ...interface{}) { 63 | logrus.SetFormatter(warnLog) 64 | logrus.Warn(args...) 65 | } 66 | 67 | // Errorf log error with color,symbol and format for a warning event 68 | func Errorf(format string, args ...interface{}) { 69 | logrus.SetFormatter(errorLog) 70 | logrus.Errorf(format, args...) 71 | } 72 | 73 | // Error log error with color adn symbol for a warning event 74 | func Error(args ...interface{}) { 75 | logrus.SetFormatter(errorLog) 76 | logrus.Error(args...) 77 | } 78 | 79 | // Fatalf log fatal with color,symbol and format for a fatal event 80 | func Fatalf(format string, args ...interface{}) { 81 | logrus.SetFormatter(fatalLog) 82 | logrus.Fatalf(format, args...) 83 | } 84 | 85 | // Fatal log fatal with color and symbol for a fatal event 86 | func Fatal(args ...interface{}) { 87 | logrus.SetFormatter(fatalLog) 88 | logrus.Fatal(args...) 89 | } 90 | 91 | // Successf log success with color,symbol and format for a success operation 92 | func Successf(format string, args ...interface{}) { 93 | logrus.SetFormatter(successLog) 94 | logrus.Infof(format, args...) 95 | } 96 | 97 | // Success log success with color and symbol, for a success operation 98 | func Success(args ...interface{}) { 99 | logrus.SetFormatter(successLog) 100 | logrus.Info(args...) 101 | } 102 | -------------------------------------------------------------------------------- /internal/log/symbol.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type Symbol string 8 | 9 | // Symbols struct contains all symbols 10 | type Symbols struct { 11 | Debug Symbol 12 | Info Symbol 13 | Warning Symbol 14 | Warn Symbol 15 | Error Symbol 16 | Fatal Symbol 17 | Success Symbol 18 | } 19 | 20 | var normal = Symbols{ 21 | Debug: Symbol("λ"), 22 | Info: Symbol("ℹ"), 23 | Success: Symbol("✔"), 24 | Warning: Symbol("⚠"), 25 | Warn: Symbol("⚠"), 26 | Error: Symbol("!!"), 27 | Fatal: Symbol("✖"), 28 | } 29 | 30 | // String returns a printable representation of Symbols struct 31 | func (s Symbols) String() string { 32 | return fmt.Sprintf("Debug: %s Info: %s Success: %s Warning: %s Error: %s Fatal: %s", s.Debug, s.Info, s.Success, s.Warning, s.Error, s.Fatal) 33 | } 34 | -------------------------------------------------------------------------------- /internal/log/wrapper.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "runtime" 7 | 8 | "github.com/sirupsen/logrus" 9 | "gopkg.in/gookit/color.v1" 10 | ) 11 | 12 | const ( 13 | DEBUG = "[DEBUG] " 14 | WARN = "[WARN] " 15 | INFO = "[INFO] " 16 | SUCCESS = "[SUCCESS] " 17 | ERROR = "[ERROR] " 18 | FATAL = "[FATAL] " 19 | ) 20 | 21 | // ROOTCALLER should be main proc 22 | const ROOTCALLER = "main.main" 23 | 24 | // REMOVELEVEL logrus stack level is 9, should be removed from stack trace 25 | const REMOVELEVEL = 10 26 | 27 | type CliLoggerFormatter struct { 28 | level logrus.Level 29 | showType string 30 | formatLevelName string 31 | prefix string 32 | } 33 | 34 | // Format implement Format interface to output custom log 35 | func (m *CliLoggerFormatter) Format(entry *logrus.Entry) ([]byte, error) { 36 | var b *bytes.Buffer 37 | if entry.Buffer != nil { 38 | b = entry.Buffer 39 | } else { 40 | b = &bytes.Buffer{} 41 | } 42 | 43 | m.levelPrintRender() 44 | 45 | timestamp := entry.Time.Format("2006-01-02 15:04:05") 46 | 47 | if m.level == logrus.ErrorLevel && logrus.GetLevel() == logrus.DebugLevel { 48 | entry.Message = addCallStackIgnoreLogrus(entry.Message) 49 | } 50 | 51 | newLog := fmt.Sprintf("%s %s %s %s\n", timestamp, m.prefix, m.formatLevelName, entry.Message) 52 | 53 | _, err := b.WriteString(newLog) 54 | if err != nil { 55 | return nil, err 56 | } 57 | return b.Bytes(), nil 58 | } 59 | 60 | // levelPrintRender render symbo and level according to type 61 | func (m *CliLoggerFormatter) levelPrintRender() { 62 | switch m.showType { 63 | case "debug": 64 | m.level = logrus.DebugLevel 65 | m.formatLevelName = color.Blue.Render(DEBUG) 66 | m.prefix = color.Blue.Render(normal.Debug) 67 | case "info": 68 | m.level = logrus.InfoLevel 69 | m.formatLevelName = color.FgLightBlue.Render(INFO) 70 | m.prefix = color.FgLightBlue.Render(normal.Info) 71 | case "warn": 72 | m.level = logrus.WarnLevel 73 | m.formatLevelName = color.Yellow.Render(WARN) 74 | m.prefix = color.Yellow.Render(normal.Warn) 75 | case "error": 76 | m.level = logrus.ErrorLevel 77 | m.formatLevelName = color.BgRed.Render(ERROR) 78 | m.prefix = color.Red.Render(normal.Error) 79 | case "fatal": 80 | m.level = logrus.FatalLevel 81 | m.formatLevelName = color.BgRed.Render(FATAL) 82 | m.prefix = color.Red.Render(normal.Fatal) 83 | case "success": 84 | m.level = logrus.InfoLevel 85 | m.formatLevelName = color.Green.Render(SUCCESS) 86 | m.prefix = color.Green.Render(normal.Success) 87 | } 88 | } 89 | 90 | type SeparatorFormatter struct{} 91 | 92 | // Format implement Format interface to output custom log 93 | func (s *SeparatorFormatter) Format(entry *logrus.Entry) ([]byte, error) { 94 | var b *bytes.Buffer 95 | if entry.Buffer != nil { 96 | b = entry.Buffer 97 | } else { 98 | b = &bytes.Buffer{} 99 | } 100 | 101 | timestamp := entry.Time.Format("2006-01-02 15:04:05") 102 | newLog := fmt.Sprintf("%s %s %s %s\n", 103 | timestamp, 104 | color.Blue.Render(normal.Info), 105 | color.Blue.Render(INFO), 106 | color.Blue.Render(fmt.Sprintf("%s %s %s", "-------------------- [ ", entry.Message, " ] --------------------"))) 107 | 108 | _, err := b.WriteString(newLog) 109 | if err != nil { 110 | return nil, err 111 | } 112 | return b.Bytes(), nil 113 | } 114 | 115 | // addCallStackIgnoreLogrus add call stack to log message without logrus stack 116 | func addCallStackIgnoreLogrus(rawMessage string) string { 117 | stackMessage := rawMessage 118 | for i := REMOVELEVEL; ; i++ { 119 | pc, file, line, _ := runtime.Caller(i) 120 | stackMessage = stackMessage + "\n -- " + file + fmt.Sprintf(" %d", line) 121 | entrance := runtime.FuncForPC(pc).Name() 122 | if entrance == ROOTCALLER || entrance == "" { 123 | break 124 | } 125 | } 126 | return stackMessage 127 | } 128 | -------------------------------------------------------------------------------- /internal/option/option.go: -------------------------------------------------------------------------------- 1 | package option 2 | 3 | // Silence is a flag to silence the output. 4 | // When OutoutFormat != "raw", Silence == true. 5 | var Silence bool 6 | -------------------------------------------------------------------------------- /internal/pkg/github/github.go: -------------------------------------------------------------------------------- 1 | package github 2 | 3 | import "fmt" 4 | 5 | func Run() { 6 | fmt.Println("github called") 7 | } 8 | -------------------------------------------------------------------------------- /internal/pkg/patch/patch.go: -------------------------------------------------------------------------------- 1 | package patch 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "os/exec" 8 | "path/filepath" 9 | "regexp" 10 | "strings" 11 | 12 | "github.com/devstream-io/devstream/internal/log" 13 | ) 14 | 15 | const ( 16 | processOptionTabToSpace ProcessOption = "tabToSpace" 17 | processOptionSpaceToTab ProcessOption = "spaceToTab" 18 | ) 19 | 20 | type ProcessOption string 21 | 22 | // Patch calls the patch command to apply a diff file to an original 23 | func Patch(workDir, patchFile string) error { 24 | log.Infof("Patching file: %s", patchFile) 25 | 26 | // Fix patch file if it mixed tab and space indentation 27 | err := fixPatchFile(workDir, patchFile) 28 | if err != nil { 29 | return fmt.Errorf("patch file fix failed: %w", err) 30 | } 31 | 32 | // Check if the patch command exists and is executable 33 | err = checkPatchCommand() 34 | if err != nil { 35 | return fmt.Errorf("patch command check failed: %w", err) 36 | } 37 | 38 | // Use the patch tool to apply the patch 39 | cmd := exec.Command("patch", "-i", patchFile, "-t", "-p0") 40 | cmd.Dir = workDir 41 | output, err := cmd.CombinedOutput() 42 | if err != nil { 43 | return fmt.Errorf("patch command failed: %w\nOutput: %s", err, string(output)) 44 | } 45 | 46 | log.Infof("Successfully patched the file") 47 | return nil 48 | } 49 | 50 | // checkPatchCommand checks if the patch command exists and is executable 51 | func checkPatchCommand() error { 52 | // Check if the patch command exists 53 | path, err := exec.LookPath("patch") 54 | if err != nil { 55 | return fmt.Errorf("patch command not found: %w", err) 56 | } 57 | 58 | // Check if the patch command is executable 59 | fileInfo, err := os.Stat(path) 60 | if err != nil { 61 | return fmt.Errorf("failed to stat patch command: %w", err) 62 | } 63 | 64 | if fileInfo.Mode()&0111 == 0 { 65 | return fmt.Errorf("patch command is not executable") 66 | } 67 | 68 | return nil 69 | } 70 | 71 | // fixPatchFile fixes the patch file if it mixed tab and space indentation. 72 | // The patch file is generated by GPT4, and it may have different indentation with the original file. 73 | // The original file path is contained in the patch file, so we can use the fix the patch file by using the original file. 74 | // If the original file uses tab indentation, we replace all spaces with tabs in the patch file. 75 | // If the original file uses space indentation, we replace all tabs with spaces in the patch file. 76 | func fixPatchFile(workDir, patchFile string) error { 77 | // Read the original file path from the patch file 78 | originalFilePath, err := extractOriginalFilePathFromPatchFile(patchFile) 79 | originalFilePath = filepath.Join(workDir, originalFilePath) 80 | 81 | if err != nil { 82 | return fmt.Errorf("failed to extract original file path from patch string: %w", err) 83 | } 84 | 85 | // Check if the original file contain tabs in the indentation 86 | original, err := os.Open(originalFilePath) 87 | if err != nil { 88 | return fmt.Errorf("failed to open original file: %w", err) 89 | } 90 | defer original.Close() 91 | 92 | hasTab := false 93 | scanner := bufio.NewScanner(original) 94 | for scanner.Scan() { 95 | line := scanner.Text() 96 | if strings.HasPrefix(line, "\t") { 97 | hasTab = true 98 | break 99 | } 100 | } 101 | 102 | if err = scanner.Err(); err != nil { 103 | return fmt.Errorf("failed to read original file: %w", err) 104 | } 105 | 106 | // The original file uses tab indentation 107 | if hasTab { 108 | // Replace all space indentation with tabs in the patch file 109 | if err = processTabSpaceSwitch(patchFile, processOptionSpaceToTab); err != nil { 110 | return fmt.Errorf("failed to process tab to space: %w", err) 111 | } 112 | // The original file uses space indentation 113 | } else { 114 | // Replace all tab indentation with spaces in the patch file 115 | if err = processTabSpaceSwitch(patchFile, processOptionTabToSpace); err != nil { 116 | return fmt.Errorf("failed to process space to tab: %w", err) 117 | } 118 | } 119 | 120 | return nil 121 | 122 | } 123 | 124 | // ExtractOriginalFilePathFromPatchString extracts the original file path from a patch string 125 | // e.g. --- pkg/patch/patch.go 2021-08-15 16:00:00.000000000 +0900 -> pkg/patch/patch.go 126 | func extractOriginalFilePathFromPatchFile(patchFile string) (string, error) { 127 | // Read content from the patch file 128 | fileContent, err := os.ReadFile(patchFile) 129 | if err != nil { 130 | return "", fmt.Errorf("failed to read patch file: %w", err) 131 | } 132 | 133 | lines := strings.Split(string(fileContent), "\n") 134 | 135 | for _, line := range lines { 136 | if strings.HasPrefix(line, "--- ") { 137 | fields := strings.Fields(line) 138 | if len(fields) > 1 { 139 | return fields[1], nil 140 | } 141 | } 142 | } 143 | 144 | return "", fmt.Errorf("original file path not found in patch string") 145 | } 146 | 147 | // processTabSpaceSwitch processes the tab/space indentation switch in a file 148 | // If the option is processOptionTabToSpace, it replaces all tabs with spaces 149 | // If the option is processOptionSpaceToTab, it replaces all spaces with tabs 150 | func processTabSpaceSwitch(filePath string, option ProcessOption) error { 151 | file, err := os.Open(filePath) 152 | if err != nil { 153 | return fmt.Errorf("failed to open file: %w", err) 154 | } 155 | defer file.Close() 156 | 157 | scanner := bufio.NewScanner(file) 158 | var processedLines []string 159 | 160 | // Matches the start of the string (^) followed by an optional + or - sign, followed by one or more groups of 4 spaces ( {4})+ 161 | spaceRegex := regexp.MustCompile(`^(\+|\-)?( {4})+`) 162 | // Matches the start of the string (^) followed by an optional + or - sign, followed by one or more tabs (\t)+ 163 | tabRegex := regexp.MustCompile(`^(\+|\-)?\t+`) 164 | 165 | for scanner.Scan() { 166 | line := scanner.Text() 167 | if option == processOptionTabToSpace { 168 | line = tabRegex.ReplaceAllStringFunc(line, func(s string) string { 169 | prefix := "" 170 | if s[0] == '+' || s[0] == '-' { 171 | prefix = string(s[0]) 172 | s = s[1:] 173 | } 174 | return prefix + strings.Repeat(" ", len(s)) 175 | }) 176 | } else if option == processOptionSpaceToTab { 177 | line = spaceRegex.ReplaceAllStringFunc(line, func(s string) string { 178 | prefix := "" 179 | if s[0] == '+' || s[0] == '-' { 180 | prefix = string(s[0]) 181 | s = s[1:] 182 | } 183 | return prefix + strings.Repeat("\t", len(s)/4) 184 | }) 185 | } else { 186 | return fmt.Errorf("invalid process option: %s", option) 187 | } 188 | processedLines = append(processedLines, line) 189 | } 190 | 191 | if err = scanner.Err(); err != nil { 192 | return fmt.Errorf("failed to read file: %w", err) 193 | } 194 | 195 | err = os.WriteFile(filePath, []byte(strings.Join(processedLines, "\n")+"\n"), 0644) 196 | if err != nil { 197 | return fmt.Errorf("failed to write file: %w", err) 198 | } 199 | 200 | return nil 201 | } 202 | -------------------------------------------------------------------------------- /internal/pkg/patch/patch_test.go: -------------------------------------------------------------------------------- 1 | package patch_test 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | "strings" 8 | "testing" 9 | 10 | . "github.com/onsi/ginkgo" 11 | . "github.com/onsi/gomega" 12 | 13 | . "github.com/devstream-io/devstream/internal/pkg/patch" 14 | ) 15 | 16 | func TestPatcher(t *testing.T) { 17 | RegisterFailHandler(Fail) 18 | RunSpecs(t, "Patcher Suite") 19 | } 20 | 21 | var _ = Describe("Patcher", func() { 22 | var ( 23 | originalFile *os.File 24 | patchFile *os.File 25 | tempDir string 26 | ) 27 | 28 | BeforeEach(func() { 29 | var err error 30 | tempDir, err = os.MkdirTemp("", "patcher-tests") 31 | Expect(err).NotTo(HaveOccurred()) 32 | 33 | originalFile, err = os.CreateTemp(tempDir, "original-*") 34 | Expect(err).NotTo(HaveOccurred()) 35 | 36 | patchFile, err = os.CreateTemp(tempDir, "patch-*") 37 | Expect(err).NotTo(HaveOccurred()) 38 | }) 39 | 40 | AfterEach(func() { 41 | err := os.RemoveAll(tempDir) 42 | Expect(err).NotTo(HaveOccurred()) 43 | }) 44 | 45 | Context("when patching a file", func() { 46 | It("successfully applies the patch to the original file", func() { 47 | originalContent := `Hello, world! 48 | This is the original file. 49 | ` 50 | 51 | err := os.WriteFile(originalFile.Name(), []byte(originalContent), 0644) 52 | Expect(err).NotTo(HaveOccurred()) 53 | 54 | patchContent := fmt.Sprintf(`--- %s 55 | +++ new-file 56 | @@ -1,2 +1,2 @@ 57 | Hello, world! 58 | -This is the original file. 59 | +This is the patched file. 60 | `, 61 | filepath.Base(originalFile.Name())) 62 | 63 | err = os.WriteFile(patchFile.Name(), []byte(patchContent), 0644) 64 | Expect(err).NotTo(HaveOccurred()) 65 | 66 | err = Patch(tempDir, patchFile.Name()) 67 | Expect(err).NotTo(HaveOccurred()) 68 | 69 | patchedContent, err := os.ReadFile(originalFile.Name()) 70 | Expect(err).NotTo(HaveOccurred()) 71 | 72 | expectedPatchedContent := `Hello, world! 73 | This is the patched file. 74 | ` 75 | patchedContentStr := string(patchedContent) 76 | Expect(patchedContentStr).To(Equal(expectedPatchedContent)) 77 | }) 78 | 79 | It("returns an error if the patch file is invalid", func() { 80 | originalContent := `Hello, world! 81 | This is the original file. 82 | ` 83 | 84 | err := os.WriteFile(originalFile.Name(), []byte(originalContent), 0644) 85 | Expect(err).NotTo(HaveOccurred()) 86 | 87 | invalidPatchContent := fmt.Sprintf(`--- %s 88 | +++ new-file 89 | @@ -1,2 +1,2 @@ 90 | `, 91 | filepath.Base(originalFile.Name())) 92 | 93 | err = os.WriteFile(patchFile.Name(), []byte(invalidPatchContent), 0644) 94 | Expect(err).NotTo(HaveOccurred()) 95 | 96 | err = Patch(tempDir, patchFile.Name()) 97 | Expect(err).To(HaveOccurred()) 98 | Expect(strings.Contains(err.Error(), "patch command failed")).To(BeTrue()) 99 | }) 100 | }) 101 | 102 | Context("when patching a file with inconsistent indentation", func() { 103 | It("successfully applies the patch with spaces to the original file with tabs", func() { 104 | originalContent := "Hello, world!\n\tThis is the original file with tabs.\n" 105 | 106 | err := os.WriteFile(originalFile.Name(), []byte(originalContent), 0644) 107 | Expect(err).NotTo(HaveOccurred()) 108 | 109 | patchContent := fmt.Sprintf(`--- %s 110 | +++ new-file 111 | @@ -1,2 +1,2 @@ 112 | Hello, world! 113 | - This is the original file with tabs. 114 | + This is the patched file with tabs. 115 | `, 116 | filepath.Base(originalFile.Name())) 117 | 118 | err = os.WriteFile(patchFile.Name(), []byte(patchContent), 0644) 119 | Expect(err).NotTo(HaveOccurred()) 120 | 121 | err = Patch(tempDir, patchFile.Name()) 122 | Expect(err).NotTo(HaveOccurred()) 123 | 124 | patchedContent, err := os.ReadFile(originalFile.Name()) 125 | Expect(err).NotTo(HaveOccurred()) 126 | 127 | expectedPatchedContent := "Hello, world!\n\tThis is the patched file with tabs.\n" 128 | Expect(string(patchedContent)).To(Equal(expectedPatchedContent)) 129 | }) 130 | 131 | It("successfully applies the patch with tabs to the original file with spaces", func() { 132 | originalContent := "Hello, world!\n This is the original file with spaces.\n" 133 | 134 | err := os.WriteFile(originalFile.Name(), []byte(originalContent), 0644) 135 | Expect(err).NotTo(HaveOccurred()) 136 | 137 | patchContent := fmt.Sprintf(`--- %s 138 | +++ new-file 139 | @@ -1,2 +1,2 @@ 140 | Hello, world! 141 | - This is the original file with spaces. 142 | + This is the patched file with spaces. 143 | `, 144 | filepath.Base(originalFile.Name())) 145 | 146 | err = os.WriteFile(patchFile.Name(), []byte(patchContent), 0644) 147 | Expect(err).NotTo(HaveOccurred()) 148 | 149 | err = Patch(tempDir, patchFile.Name()) 150 | Expect(err).NotTo(HaveOccurred()) 151 | 152 | patchedContent, err := os.ReadFile(originalFile.Name()) 153 | Expect(err).NotTo(HaveOccurred()) 154 | 155 | expectedPatchedContent := "Hello, world!\n This is the patched file with spaces.\n" 156 | Expect(string(patchedContent)).To(Equal(expectedPatchedContent)) 157 | }) 158 | }) 159 | }) 160 | -------------------------------------------------------------------------------- /internal/pkg/scaffold/scaffold.go: -------------------------------------------------------------------------------- 1 | package scaffold 2 | 3 | func Scaffold(tree string) error { 4 | return nil 5 | } 6 | 7 | // parseTreeToList parses the directory tree represented by a string and 8 | // returns a list of directories and files. 9 | // for example input:" 10 | // testdir/ 11 | // ├── dir1/ 12 | // │ ├── file1.go 13 | // │ └── dir2/ 14 | // │ ├── file1.go 15 | // │ └── file2.go 16 | // └── FILE3.md 17 | // " 18 | // output: 19 | // 20 | // []string{ 21 | // "testdir/", 22 | // "testdir/dir1/", 23 | // "testdir/dir1/file1.go", 24 | // "testdir/dir1/dir2/", 25 | // "testdir/dir1/dir2/file1.go", 26 | // "testdir/dir1/dir2/file2.go", 27 | // } 28 | //func parseTreeToList(tree string) ([]string, error) { 29 | // tree = strings.ReplaceAll(tree, "\r\n", "\n") 30 | // tree = strings.ReplaceAll(tree, "\r", "\n") 31 | // tree = strings.ReplaceAll(tree, "\t", "") 32 | // tree = strings.ReplaceAll(tree, "\n\n", "\n") 33 | // tree = strings.ReplaceAll(tree, "─", "-") 34 | // tree = strings.ReplaceAll(tree, "│", "|") 35 | // 36 | // lines := strings.Split(tree, "\n") 37 | // var result []string 38 | // 39 | // for _, line := range lines { 40 | // line = strings.TrimSpace(line) 41 | // 42 | // if len(line) == 0 { 43 | // continue 44 | // } 45 | // 46 | // level := 0 47 | // for ; strings.HasPrefix(line, " "); level++ { 48 | // line = line[2:] 49 | // } 50 | // 51 | // prefix := strings.Repeat(" ", level) 52 | // 53 | // if strings.HasSuffix(line, "/") { 54 | // result = append(result, prefix+line) 55 | // } else { 56 | // result = append(result, prefix+line) 57 | // } 58 | // 59 | // } 60 | // 61 | // return result, nil 62 | //} 63 | // 64 | //func ParseTree(tree string) ([]string, error) { 65 | // var result []string 66 | // 67 | // lines := strings.Split(tree, "\n") 68 | // for _, line := range lines { 69 | // if strings.TrimSpace(line) == "" { 70 | // continue 71 | // } 72 | // 73 | // parts := strings.Split(line, " ") 74 | // level := strings.Count(parts[0], "│") + strings.Count(parts[0], "└") + strings.Count(parts[0], "├") 75 | // name := strings.TrimSpace(parts[len(parts)-1]) 76 | // 77 | // // Construct the full path by combining the names of all parent directories 78 | // path := "" 79 | // for i := 1; i < level; i++ { 80 | // if len(result) < i { 81 | // return nil, fmt.Errorf("parent directory not found: %s", line) 82 | // } 83 | // path += result[i-1] + "/" 84 | // } 85 | // path += name 86 | // 87 | // result = append(result, path) 88 | // } 89 | // 90 | // return result, nil 91 | //} 92 | -------------------------------------------------------------------------------- /internal/pkg/scaffold/scaffold_test.go: -------------------------------------------------------------------------------- 1 | package scaffold_test 2 | -------------------------------------------------------------------------------- /internal/pkg/scaffold/tree/parse.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | import "strings" 4 | 5 | // testdir/ 6 | // ├── dir1/ 7 | // │ ├── file1.go 8 | // │ └── dir2/ 9 | // │ ├── file1.go 10 | // │ └── file2.go 11 | // └── FILE3.md 12 | func ParseTree(treeText string) *TreeNode { 13 | lines := strings.Split(treeText, "\n") 14 | rootLine := strings.TrimSpace(lines[0]) 15 | rootName := strings.TrimSuffix(rootLine, "/") 16 | root := NewTreeNode(rootName, true) 17 | stack := []*TreeNode{root} 18 | 19 | for _, line := range lines[1:] { 20 | // dir1 as an example, the indent is 3+2=5 in "├── dir1/". 21 | indent := strings.LastIndex(line, "──") + 2 22 | // line[indent:] apply to dir1/, the result is " dir1/" 23 | // name is "dir1/" 24 | name := strings.TrimSpace(line[indent:]) 25 | isDir := strings.HasSuffix(name, "/") 26 | if isDir { 27 | name = strings.TrimSuffix(name, "/") 28 | } 29 | 30 | node := NewTreeNode(name, isDir) 31 | parent := stack[indent/4] 32 | parent.AddChild(node) 33 | 34 | if isDir { 35 | stack = append(stack, node) 36 | } else { 37 | stack = append(stack[:indent/4+1], node) 38 | } 39 | } 40 | return root 41 | } 42 | -------------------------------------------------------------------------------- /internal/pkg/scaffold/tree/tree.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | import "fmt" 4 | 5 | type TreeNode struct { 6 | Name string 7 | IsDir bool 8 | Children []*TreeNode 9 | } 10 | 11 | func NewTreeNode(name string, isDir bool) *TreeNode { 12 | return &TreeNode{ 13 | Name: name, 14 | IsDir: isDir, 15 | Children: []*TreeNode{}, 16 | } 17 | } 18 | 19 | func (t *TreeNode) AddChild(child *TreeNode) { 20 | t.Children = append(t.Children, child) 21 | } 22 | 23 | func (t *TreeNode) PrintTree(prefix string) { 24 | if t.IsDir { 25 | fmt.Println(prefix + t.Name + "/") 26 | } else { 27 | fmt.Println(prefix + t.Name) 28 | } 29 | for _, child := range t.Children { 30 | child.PrintTree(prefix + " ") 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /internal/response/response.go: -------------------------------------------------------------------------------- 1 | package response 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/devstream-io/devstream/internal/log" 7 | 8 | "gopkg.in/yaml.v3" 9 | ) 10 | 11 | type StatusCode int 12 | type MessageText string 13 | 14 | type Response struct { 15 | Status StatusCode `json:"status" yaml:"status"` 16 | Message MessageText `json:"message" yaml:"message"` 17 | Log string `json:"log" yaml:"log"` 18 | } 19 | 20 | var ( 21 | StatusOK StatusCode = 0 22 | StatusError StatusCode = 1 23 | ) 24 | 25 | var ( 26 | MessageOK MessageText = "OK" 27 | MessageError MessageText = "ERROR" 28 | ) 29 | 30 | func New(status StatusCode, message MessageText, log string) *Response { 31 | return &Response{ 32 | Status: status, 33 | Message: message, 34 | Log: log, 35 | } 36 | } 37 | 38 | func (r *Response) Print(format string) { 39 | log.Debugf("Format: %s", format) 40 | switch format { 41 | case "json": 42 | r.printJSON() 43 | case "yaml": 44 | r.printYAML() 45 | default: 46 | r.printRaw() 47 | } 48 | } 49 | 50 | func (r *Response) printRaw() { 51 | fmt.Println(r.toRaw()) 52 | } 53 | 54 | func (r *Response) printJSON() { 55 | fmt.Println(r.toJSON()) 56 | } 57 | 58 | func (r *Response) printYAML() { 59 | fmt.Println(r.toYAML()) 60 | } 61 | 62 | func (r *Response) toRaw() string { 63 | return r.Log 64 | } 65 | 66 | func (r *Response) toJSON() string { 67 | str, err := json.Marshal(r) 68 | if err != nil { 69 | return err.Error() 70 | } 71 | return string(str) 72 | } 73 | 74 | func (r *Response) toYAML() string { 75 | str, err := yaml.Marshal(r) 76 | if err != nil { 77 | return err.Error() 78 | } 79 | return string(str) 80 | } 81 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2023 NAME HERE 3 | 4 | */ 5 | package main 6 | 7 | import "github.com/devstream-io/devstream/cmd" 8 | 9 | func main() { 10 | cmd.Execute() 11 | } 12 | --------------------------------------------------------------------------------