Compare commits
No commits in common. "main" and "v0.4.0" have entirely different histories.
17
.drone.yml
17
.drone.yml
@ -15,25 +15,13 @@ steps:
|
|||||||
- push
|
- push
|
||||||
- pull_request
|
- pull_request
|
||||||
- tag
|
- tag
|
||||||
- name: build-dev
|
|
||||||
image: golang:1.18.3-alpine3.16
|
|
||||||
commands:
|
|
||||||
- "apk add --update --no-cache make"
|
|
||||||
- "make build"
|
|
||||||
when:
|
|
||||||
event:
|
|
||||||
- push
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
cpu: 1000
|
|
||||||
memory: 1024MiB
|
|
||||||
- name: build
|
- name: build
|
||||||
image: goreleaser/goreleaser
|
image: goreleaser/goreleaser
|
||||||
commands:
|
commands:
|
||||||
- curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin v0.64.0
|
|
||||||
- goreleaser build --snapshot
|
- goreleaser build --snapshot
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
|
- push
|
||||||
- pull_request
|
- pull_request
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
@ -57,10 +45,7 @@ steps:
|
|||||||
from_secret: GPG_PRIVATE_KEY
|
from_secret: GPG_PRIVATE_KEY
|
||||||
GPG_FINGERPRINT:
|
GPG_FINGERPRINT:
|
||||||
from_secret: GPG_FINGERPRINT
|
from_secret: GPG_FINGERPRINT
|
||||||
GPG_PRIVATE_KEY_BASE64:
|
|
||||||
from_secret: GPG_PRIVATE_KEY_BASE64
|
|
||||||
commands:
|
commands:
|
||||||
- curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin v0.64.0
|
|
||||||
- apk add gpg-agent
|
- apk add gpg-agent
|
||||||
- gpg-agent --daemon --default-cache-ttl 7200
|
- gpg-agent --daemon --default-cache-ttl 7200
|
||||||
- echo $GPG_PRIVATE_KEY_BASE64 | base64 -d | gpg --import --batch --no-tty
|
- echo $GPG_PRIVATE_KEY_BASE64 | base64 -d | gpg --import --batch --no-tty
|
||||||
|
28
.github/ISSUE_TEMPLATE/bug_report.md
vendored
28
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,28 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Create a report to improve the provider
|
|
||||||
title: ''
|
|
||||||
labels: 'bug'
|
|
||||||
assignees: ''
|
|
||||||
---
|
|
||||||
|
|
||||||
**Describe the bug**
|
|
||||||
A clear and concise description of what the bug is.
|
|
||||||
|
|
||||||
**To Reproduce**
|
|
||||||
Steps to reproduce the behavior:
|
|
||||||
|
|
||||||
**Expected behavior**
|
|
||||||
A clear and concise description of what you expected to happen.
|
|
||||||
|
|
||||||
**Log Output**
|
|
||||||
If applicable, add logs to help explain your problem.
|
|
||||||
|
|
||||||
**Additional Data**
|
|
||||||
Important for reproducability.
|
|
||||||
|
|
||||||
- Terraform Version
|
|
||||||
|
|
||||||
- Operating System
|
|
||||||
|
|
||||||
- Provider Version
|
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Suggest an idea for this provider
|
|
||||||
title: ''
|
|
||||||
labels: 'enhancement'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
|
||||||
A clear and concise description of what you want to happen.
|
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context or screenshots about the feature request here.
|
|
15
.github/dependabot.yml
vendored
15
.github/dependabot.yml
vendored
@ -1,15 +0,0 @@
|
|||||||
# To get started with Dependabot version updates, you'll need to specify which
|
|
||||||
# package ecosystems to update and where the package manifests are located.
|
|
||||||
# Please see the documentation for all configuration options:
|
|
||||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
||||||
|
|
||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "gomod"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "weekly"
|
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "weekly"
|
|
34
.github/workflows/release.yml
vendored
34
.github/workflows/release.yml
vendored
@ -18,29 +18,31 @@ jobs:
|
|||||||
goreleaser:
|
goreleaser:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
-
|
||||||
|
name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
- name: Unshallow
|
-
|
||||||
|
name: Unshallow
|
||||||
run: git fetch --prune --unshallow
|
run: git fetch --prune --unshallow
|
||||||
- name: Set up Go
|
-
|
||||||
uses: actions/setup-go@v4
|
name: Set up Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.18
|
go-version: 1.18
|
||||||
- name: Import GPG key
|
-
|
||||||
|
name: Import GPG key
|
||||||
id: import_gpg
|
id: import_gpg
|
||||||
uses: crazy-max/ghaction-import-gpg@v5.3.0
|
uses: hashicorp/ghaction-import-gpg@v2.1.0
|
||||||
with:
|
env:
|
||||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
# These secrets will need to be configured for the repository:
|
||||||
passphrase: ${{ secrets.PASSPHRASE }}
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
- name: setup-syft
|
PASSPHRASE: ${{ secrets.PASSPHRASE }}
|
||||||
run: |
|
-
|
||||||
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | \
|
name: Run GoReleaser
|
||||||
sh -s -- -b /usr/local/bin v0.64.0
|
uses: goreleaser/goreleaser-action@v3.0.0
|
||||||
- name: Run GoReleaser
|
|
||||||
uses: goreleaser/goreleaser-action@v4.3.0
|
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
args: release --clean
|
args: release --rm-dist
|
||||||
env:
|
env:
|
||||||
GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
|
GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
|
||||||
# GitHub sets this automatically
|
# GitHub sets this automatically
|
||||||
|
@ -41,8 +41,6 @@ checksum:
|
|||||||
name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json'
|
name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json'
|
||||||
name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS'
|
name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS'
|
||||||
algorithm: sha256
|
algorithm: sha256
|
||||||
sboms:
|
|
||||||
- artifacts: archive
|
|
||||||
signs:
|
signs:
|
||||||
- artifacts: checksum
|
- artifacts: checksum
|
||||||
args:
|
args:
|
||||||
|
@ -1,128 +0,0 @@
|
|||||||
# Contributor Covenant Code of Conduct
|
|
||||||
|
|
||||||
## Our Pledge
|
|
||||||
|
|
||||||
We as members, contributors, and leaders pledge to make participation in our
|
|
||||||
community a harassment-free experience for everyone, regardless of age, body
|
|
||||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
||||||
identity and expression, level of experience, education, socio-economic status,
|
|
||||||
nationality, personal appearance, race, religion, or sexual identity
|
|
||||||
and orientation.
|
|
||||||
|
|
||||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
|
||||||
diverse, inclusive, and healthy community.
|
|
||||||
|
|
||||||
## Our Standards
|
|
||||||
|
|
||||||
Examples of behavior that contributes to a positive environment for our
|
|
||||||
community include:
|
|
||||||
|
|
||||||
* Demonstrating empathy and kindness toward other people
|
|
||||||
* Being respectful of differing opinions, viewpoints, and experiences
|
|
||||||
* Giving and gracefully accepting constructive feedback
|
|
||||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
|
||||||
and learning from the experience
|
|
||||||
* Focusing on what is best not just for us as individuals, but for the
|
|
||||||
overall community
|
|
||||||
|
|
||||||
Examples of unacceptable behavior include:
|
|
||||||
|
|
||||||
* The use of sexualized language or imagery, and sexual attention or
|
|
||||||
advances of any kind
|
|
||||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
|
||||||
* Public or private harassment
|
|
||||||
* Publishing others' private information, such as a physical or email
|
|
||||||
address, without their explicit permission
|
|
||||||
* Other conduct which could reasonably be considered inappropriate in a
|
|
||||||
professional setting
|
|
||||||
|
|
||||||
## Enforcement Responsibilities
|
|
||||||
|
|
||||||
Community leaders are responsible for clarifying and enforcing our standards of
|
|
||||||
acceptable behavior and will take appropriate and fair corrective action in
|
|
||||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
|
||||||
or harmful.
|
|
||||||
|
|
||||||
Community leaders have the right and responsibility to remove, edit, or reject
|
|
||||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
|
||||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
|
||||||
decisions when appropriate.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
This Code of Conduct applies within all community spaces, and also applies when
|
|
||||||
an individual is officially representing the community in public spaces.
|
|
||||||
Examples of representing our community include using an official e-mail address,
|
|
||||||
posting via an official social media account, or acting as an appointed
|
|
||||||
representative at an online or offline event.
|
|
||||||
|
|
||||||
## Enforcement
|
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
||||||
reported to the community leaders responsible for enforcement at
|
|
||||||
`lerentis at uploadfilter24 dot eu`.
|
|
||||||
All complaints will be reviewed and investigated promptly and fairly.
|
|
||||||
|
|
||||||
All community leaders are obligated to respect the privacy and security of the
|
|
||||||
reporter of any incident.
|
|
||||||
|
|
||||||
## Enforcement Guidelines
|
|
||||||
|
|
||||||
Community leaders will follow these Community Impact Guidelines in determining
|
|
||||||
the consequences for any action they deem in violation of this Code of Conduct:
|
|
||||||
|
|
||||||
### 1. Correction
|
|
||||||
|
|
||||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
|
||||||
unprofessional or unwelcome in the community.
|
|
||||||
|
|
||||||
**Consequence**: A private, written warning from community leaders, providing
|
|
||||||
clarity around the nature of the violation and an explanation of why the
|
|
||||||
behavior was inappropriate. A public apology may be requested.
|
|
||||||
|
|
||||||
### 2. Warning
|
|
||||||
|
|
||||||
**Community Impact**: A violation through a single incident or series
|
|
||||||
of actions.
|
|
||||||
|
|
||||||
**Consequence**: A warning with consequences for continued behavior. No
|
|
||||||
interaction with the people involved, including unsolicited interaction with
|
|
||||||
those enforcing the Code of Conduct, for a specified period of time. This
|
|
||||||
includes avoiding interactions in community spaces as well as external channels
|
|
||||||
like social media. Violating these terms may lead to a temporary or
|
|
||||||
permanent ban.
|
|
||||||
|
|
||||||
### 3. Temporary Ban
|
|
||||||
|
|
||||||
**Community Impact**: A serious violation of community standards, including
|
|
||||||
sustained inappropriate behavior.
|
|
||||||
|
|
||||||
**Consequence**: A temporary ban from any sort of interaction or public
|
|
||||||
communication with the community for a specified period of time. No public or
|
|
||||||
private interaction with the people involved, including unsolicited interaction
|
|
||||||
with those enforcing the Code of Conduct, is allowed during this period.
|
|
||||||
Violating these terms may lead to a permanent ban.
|
|
||||||
|
|
||||||
### 4. Permanent Ban
|
|
||||||
|
|
||||||
**Community Impact**: Demonstrating a pattern of violation of community
|
|
||||||
standards, including sustained inappropriate behavior, harassment of an
|
|
||||||
individual, or aggression toward or disparagement of classes of individuals.
|
|
||||||
|
|
||||||
**Consequence**: A permanent ban from any sort of public interaction within
|
|
||||||
the community.
|
|
||||||
|
|
||||||
## Attribution
|
|
||||||
|
|
||||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
||||||
version 2.0, available at
|
|
||||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
|
||||||
|
|
||||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
|
||||||
enforcement ladder](https://github.com/mozilla/diversity).
|
|
||||||
|
|
||||||
[homepage]: https://www.contributor-covenant.org
|
|
||||||
|
|
||||||
For answers to common questions about this code of conduct, see the FAQ at
|
|
||||||
https://www.contributor-covenant.org/faq. Translations are available at
|
|
||||||
https://www.contributor-covenant.org/translations.
|
|
22
LICENSE
22
LICENSE
@ -1,22 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2022 lerentis, https://git.uploadfilter24.eu/lerentis
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
12
Makefile
12
Makefile
@ -1,11 +1,9 @@
|
|||||||
TEST?=./gitea
|
TEST?=./gitea
|
||||||
GOFMT_FILES?=$$(find . -name '*.go' |grep -v vendor)
|
GOFMT_FILES?=$$(find . -name '*.go' |grep -v vendor)
|
||||||
ARCH?=$$(uname -m)
|
|
||||||
KERNEL?=$$(uname -s | tr '[:upper:]' '[:lower:]')
|
|
||||||
|
|
||||||
GOFMT ?= gofmt -s
|
GOFMT ?= gofmt -s
|
||||||
|
|
||||||
VERSION = 0.16.0
|
VERSION = 0.4.0
|
||||||
|
|
||||||
test: fmt-check
|
test: fmt-check
|
||||||
go test -i $(TEST) || exit 1
|
go test -i $(TEST) || exit 1
|
||||||
@ -36,8 +34,6 @@ build:
|
|||||||
go build -ldflags="-X 'main.Version=${VERSION}'" -o terraform-provider-gitea_${VERSION}
|
go build -ldflags="-X 'main.Version=${VERSION}'" -o terraform-provider-gitea_${VERSION}
|
||||||
install: build
|
install: build
|
||||||
@echo installing to
|
@echo installing to
|
||||||
@echo ~/.terraform.d/plugins/terraform.local/lerentis/gitea/${VERSION}/${KERNEL}_${ARCH}/terraform-provider-gitea_${VERSION}
|
@echo ~/.terraform.d/plugins/terraform.local/lerentis/gitea/${VERSION}/linux_amd64/terraform-provider-gitea_${VERSION}
|
||||||
@mkdir -p ~/.terraform.d/plugins/terraform.local/lerentis/gitea/${VERSION}/${KERNEL}_${ARCH}
|
@mkdir -p ~/.terraform.d/plugins/terraform.local/lerentis/gitea/${VERSION}/linux_amd64
|
||||||
@mv terraform-provider-gitea_${VERSION} ~/.terraform.d/plugins/terraform.local/lerentis/gitea/${VERSION}/${KERNEL}_${ARCH}/terraform-provider-gitea_${VERSION}
|
@mv terraform-provider-gitea_${VERSION} ~/.terraform.d/plugins/terraform.local/lerentis/gitea/${VERSION}/linux_amd64/terraform-provider-gitea_${VERSION}
|
||||||
doc:
|
|
||||||
tfplugindocs
|
|
||||||
|
@ -17,7 +17,7 @@ terraform {
|
|||||||
required_providers {
|
required_providers {
|
||||||
gitea = {
|
gitea = {
|
||||||
source = "Lerentis/gitea"
|
source = "Lerentis/gitea"
|
||||||
version = "0.16.0"
|
version = "0.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ terraform {
|
|||||||
required_providers {
|
required_providers {
|
||||||
gitea = {
|
gitea = {
|
||||||
source = "Lerentis/gitea"
|
source = "Lerentis/gitea"
|
||||||
version = "0.16.0"
|
version = "0.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
---
|
|
||||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
|
||||||
page_title: "gitea_fork Resource - terraform-provider-gitea"
|
|
||||||
subcategory: ""
|
|
||||||
description: |-
|
|
||||||
gitea_fork manages repository fork to the current user or an organisation
|
|
||||||
Forking a repository to a dedicated user is currently unsupported
|
|
||||||
Creating a fork using this resource without an organisation will create the fork in the executors name
|
|
||||||
---
|
|
||||||
|
|
||||||
# gitea_fork (Resource)
|
|
||||||
|
|
||||||
`gitea_fork` manages repository fork to the current user or an organisation
|
|
||||||
Forking a repository to a dedicated user is currently unsupported
|
|
||||||
Creating a fork using this resource without an organisation will create the fork in the executors name
|
|
||||||
|
|
||||||
## Example Usage
|
|
||||||
|
|
||||||
```terraform
|
|
||||||
resource "gitea_org" "org1" {
|
|
||||||
name = "org1"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_org" "org2" {
|
|
||||||
name = "org2"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_repository" "repo1_in_org1" {
|
|
||||||
username = gitea_org.org1.name
|
|
||||||
name = "repo1-in-org1"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_fork" "user_fork_of_repo1_in_org1" {
|
|
||||||
owner = gitea_org.org1.name
|
|
||||||
repo = gitea_repository.repo1_in_org1.name
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_fork" "org2_fork_of_repo1_in_org1" {
|
|
||||||
owner = gitea_org.org1.name
|
|
||||||
repo = gitea_repository.repo1_in_org1.name
|
|
||||||
organization = gitea_org.org2.name
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- schema generated by tfplugindocs -->
|
|
||||||
## Schema
|
|
||||||
|
|
||||||
### Required
|
|
||||||
|
|
||||||
- `owner` (String) The owner or owning organization of the repository to fork
|
|
||||||
- `repo` (String) The name of the repository to fork
|
|
||||||
|
|
||||||
### Optional
|
|
||||||
|
|
||||||
- `organization` (String) The organization that owns the forked repo
|
|
||||||
|
|
||||||
### Read-Only
|
|
||||||
|
|
||||||
- `id` (String) The ID of this resource.
|
|
||||||
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
|||||||
---
|
|
||||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
|
||||||
page_title: "gitea_git_hook Resource - terraform-provider-gitea"
|
|
||||||
subcategory: ""
|
|
||||||
description: |-
|
|
||||||
gitea_git_hook manages git hooks on a repository.
|
|
||||||
import is currently not supported
|
|
||||||
WARNING: using this resource requires to enable server side hookswhich are known to cause security issues https://github.com/go-gitea/gitea/pull/13058!
|
|
||||||
if you want to procede, you need to enable server side hooks as stated here https://docs.gitea.io/en-us/config-cheat-sheet/#security-security
|
|
||||||
---
|
|
||||||
|
|
||||||
# gitea_git_hook (Resource)
|
|
||||||
|
|
||||||
`gitea_git_hook` manages git hooks on a repository.
|
|
||||||
import is currently not supported
|
|
||||||
|
|
||||||
WARNING: using this resource requires to enable server side hookswhich are known to cause [security issues](https://github.com/go-gitea/gitea/pull/13058)!
|
|
||||||
|
|
||||||
if you want to procede, you need to enable server side hooks as stated [here](https://docs.gitea.io/en-us/config-cheat-sheet/#security-security)
|
|
||||||
|
|
||||||
## Example Usage
|
|
||||||
|
|
||||||
```terraform
|
|
||||||
resource "gitea_org" "test_org" {
|
|
||||||
name = "test-org"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_repository" "org_repo" {
|
|
||||||
username = gitea_org.test_org.name
|
|
||||||
name = "org-test-repo"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_git_hook" "org_repo_post_receive" {
|
|
||||||
name = "post-receive"
|
|
||||||
user = gitea_org.test_org.name
|
|
||||||
repo = gitea_repository.org_repo.name
|
|
||||||
content = file("${path.module}/post-receive.sh")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- schema generated by tfplugindocs -->
|
|
||||||
## Schema
|
|
||||||
|
|
||||||
### Required
|
|
||||||
|
|
||||||
- `content` (String) Content of the git hook
|
|
||||||
- `name` (String) Name of the git hook to configure
|
|
||||||
- `repo` (String) The repository that this hook belongs too.
|
|
||||||
- `user` (String) The user (or organisation) owning the repo this hook belongs too
|
|
||||||
|
|
||||||
### Read-Only
|
|
||||||
|
|
||||||
- `id` (String) The ID of this resource.
|
|
||||||
|
|
||||||
|
|
@ -20,10 +20,6 @@ Handling [gitea oauth application](https://docs.gitea.io/en-us/oauth2-provider/)
|
|||||||
- `name` (String) OAuth Application name
|
- `name` (String) OAuth Application name
|
||||||
- `redirect_uris` (Set of String) Accepted redirect URIs
|
- `redirect_uris` (Set of String) Accepted redirect URIs
|
||||||
|
|
||||||
### Optional
|
|
||||||
|
|
||||||
- `confidential_client` (Boolean) If set to false, it will be a public client (PKCE will be required)
|
|
||||||
|
|
||||||
### Read-Only
|
### Read-Only
|
||||||
|
|
||||||
- `client_id` (String) OAuth2 Application client id
|
- `client_id` (String) OAuth2 Application client id
|
||||||
|
@ -46,6 +46,5 @@ resource "gitea_repository" "org_repo" {
|
|||||||
|
|
||||||
- `avatar_url` (String)
|
- `avatar_url` (String)
|
||||||
- `id` (String) The ID of this resource.
|
- `id` (String) The ID of this resource.
|
||||||
- `repos` (List of String) List of all Repositories that are part of this organisation
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
---
|
|
||||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
|
||||||
page_title: "gitea_public_key Resource - terraform-provider-gitea"
|
|
||||||
subcategory: ""
|
|
||||||
description: |-
|
|
||||||
gitea_public_key manages ssh key that are associated with users.
|
|
||||||
---
|
|
||||||
|
|
||||||
# gitea_public_key (Resource)
|
|
||||||
|
|
||||||
`gitea_public_key` manages ssh key that are associated with users.
|
|
||||||
|
|
||||||
## Example Usage
|
|
||||||
|
|
||||||
```terraform
|
|
||||||
resource "gitea_user" "test" {
|
|
||||||
username = "test"
|
|
||||||
login_name = "test"
|
|
||||||
password = "Geheim1!"
|
|
||||||
email = "test@user.dev"
|
|
||||||
must_change_password = false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
resource "gitea_public_key" "test_user_key" {
|
|
||||||
title = "test"
|
|
||||||
key = file("${path.module}/id_ed25519.pub")
|
|
||||||
username = gitea_user.test.username
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- schema generated by tfplugindocs -->
|
|
||||||
## Schema
|
|
||||||
|
|
||||||
### Required
|
|
||||||
|
|
||||||
- `key` (String, Sensitive) An armored SSH key to add
|
|
||||||
- `title` (String) Title of the key to add
|
|
||||||
- `username` (String) User to associate with the added key
|
|
||||||
|
|
||||||
### Optional
|
|
||||||
|
|
||||||
- `read_only` (Boolean) Describe if the key has only read access or read/write
|
|
||||||
|
|
||||||
### Read-Only
|
|
||||||
|
|
||||||
- `created` (String)
|
|
||||||
- `fingerprint` (String)
|
|
||||||
- `id` (String) The ID of this resource.
|
|
||||||
- `type` (String)
|
|
||||||
|
|
||||||
|
|
@ -7,7 +7,6 @@ description: |-
|
|||||||
Per default this repository will be initializiled with the provided configuration (gitignore, License etc.).
|
Per default this repository will be initializiled with the provided configuration (gitignore, License etc.).
|
||||||
If the username property is set to a organisation name, the provider will try to look if this organisation exists and create the repository under the organisation scope.
|
If the username property is set to a organisation name, the provider will try to look if this organisation exists and create the repository under the organisation scope.
|
||||||
Repository migrations have some properties that are not available to regular repositories. These are all prefixed with migration_.
|
Repository migrations have some properties that are not available to regular repositories. These are all prefixed with migration_.
|
||||||
Codeberg.org does currently not allow mirrors to be created. See FAQ Section of CodeBerg for more information: https://docs.codeberg.org/getting-started/faq/#why-am-i-not-allowed-to-set-up-an-automatic-mirror
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# gitea_repository (Resource)
|
# gitea_repository (Resource)
|
||||||
@ -18,7 +17,6 @@ Per default this repository will be initializiled with the provided configuratio
|
|||||||
If the `username` property is set to a organisation name, the provider will try to look if this organisation exists and create the repository under the organisation scope.
|
If the `username` property is set to a organisation name, the provider will try to look if this organisation exists and create the repository under the organisation scope.
|
||||||
|
|
||||||
Repository migrations have some properties that are not available to regular repositories. These are all prefixed with `migration_`.
|
Repository migrations have some properties that are not available to regular repositories. These are all prefixed with `migration_`.
|
||||||
Codeberg.org does currently not allow mirrors to be created. See FAQ Section of CodeBerg for more information: https://docs.codeberg.org/getting-started/faq/#why-am-i-not-allowed-to-set-up-an-automatic-mirror
|
|
||||||
|
|
||||||
## Example Usage
|
## Example Usage
|
||||||
|
|
||||||
@ -41,16 +39,6 @@ resource "gitea_repository" "mirror" {
|
|||||||
migration_service = "gitea"
|
migration_service = "gitea"
|
||||||
migration_service_auth_token = var.gitea_mirror_token
|
migration_service_auth_token = var.gitea_mirror_token
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "gitea_repository" "clone" {
|
|
||||||
username = "lerentis"
|
|
||||||
name = "terraform-provider-gitea-clone"
|
|
||||||
description = "Clone of Terraform Provider"
|
|
||||||
mirror = false
|
|
||||||
migration_clone_address = "https://git.uploadfilter24.eu/lerentis/terraform-provider-gitea.git"
|
|
||||||
migration_service = "gitea"
|
|
||||||
migration_service_auth_token = var.gitea_clone_token
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- schema generated by tfplugindocs -->
|
<!-- schema generated by tfplugindocs -->
|
||||||
@ -84,8 +72,7 @@ Need to exist in the gitea instance
|
|||||||
Need to exist in the gitea instance
|
Need to exist in the gitea instance
|
||||||
- `license` (String) The license under which the source code of this repository should be.
|
- `license` (String) The license under which the source code of this repository should be.
|
||||||
Need to exist in the gitea instance
|
Need to exist in the gitea instance
|
||||||
- `migration_clone_address` (String)
|
- `migration_clone_addresse` (String)
|
||||||
- `migration_clone_addresse` (String) DEPRECATED in favor of `migration_clone_address`
|
|
||||||
- `migration_issue_labels` (Boolean)
|
- `migration_issue_labels` (Boolean)
|
||||||
- `migration_lfs` (Boolean)
|
- `migration_lfs` (Boolean)
|
||||||
- `migration_lfs_endpoint` (String)
|
- `migration_lfs_endpoint` (String)
|
||||||
@ -104,14 +91,11 @@ Need to exist in the gitea instance
|
|||||||
|
|
||||||
### Read-Only
|
### Read-Only
|
||||||
|
|
||||||
- `clone_url` (String)
|
|
||||||
- `created` (String)
|
- `created` (String)
|
||||||
- `html_url` (String)
|
|
||||||
- `id` (String) The ID of this resource.
|
- `id` (String) The ID of this resource.
|
||||||
- `permission_admin` (Boolean)
|
- `permission_admin` (Boolean)
|
||||||
- `permission_pull` (Boolean)
|
- `permission_pull` (Boolean)
|
||||||
- `permission_push` (Boolean)
|
- `permission_push` (Boolean)
|
||||||
- `ssh_url` (String)
|
|
||||||
- `updated` (String)
|
- `updated` (String)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
---
|
|
||||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
|
||||||
page_title: "gitea_repository_key Resource - terraform-provider-gitea"
|
|
||||||
subcategory: ""
|
|
||||||
description: |-
|
|
||||||
gitea_repository_key manages a deploy key for a single gitea_repository.
|
|
||||||
Every key needs a unique name and unique key, i.e. no key can be added twice to the same repo
|
|
||||||
---
|
|
||||||
|
|
||||||
# gitea_repository_key (Resource)
|
|
||||||
|
|
||||||
`gitea_repository_key` manages a deploy key for a single gitea_repository.
|
|
||||||
|
|
||||||
Every key needs a unique name and unique key, i.e. no key can be added twice to the same repo
|
|
||||||
|
|
||||||
## Example Usage
|
|
||||||
|
|
||||||
```terraform
|
|
||||||
terraform {
|
|
||||||
required_providers {
|
|
||||||
tls = {
|
|
||||||
source = "hashicorp/tls"
|
|
||||||
version = "4.0.4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "tls_private_key" "example" {
|
|
||||||
type = "RSA"
|
|
||||||
rsa_bits = 4096
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_repository" "example" {
|
|
||||||
name = "example"
|
|
||||||
private = true
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_repository_key" "example" {
|
|
||||||
repository = gitea_repository.example.id
|
|
||||||
title = "Example Deploy Key"
|
|
||||||
read_only = true
|
|
||||||
key = tls_private_key.example.public_key_openssh
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- schema generated by tfplugindocs -->
|
|
||||||
## Schema
|
|
||||||
|
|
||||||
### Required
|
|
||||||
|
|
||||||
- `key` (String) Armored SSH key to add
|
|
||||||
- `repository` (Number) The ID of the repository where the deploy key belongs to
|
|
||||||
- `title` (String) Name of the deploy key
|
|
||||||
|
|
||||||
### Optional
|
|
||||||
|
|
||||||
- `read_only` (Boolean) Whether this key has read or read/write access
|
|
||||||
|
|
||||||
### Read-Only
|
|
||||||
|
|
||||||
- `id` (String) The ID of this resource.
|
|
||||||
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
|||||||
---
|
|
||||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
|
||||||
page_title: "gitea_team Resource - terraform-provider-gitea"
|
|
||||||
subcategory: ""
|
|
||||||
description: |-
|
|
||||||
gitea_team manages Team that are part of an organisation.
|
|
||||||
---
|
|
||||||
|
|
||||||
# gitea_team (Resource)
|
|
||||||
|
|
||||||
`gitea_team` manages Team that are part of an organisation.
|
|
||||||
|
|
||||||
## Example Usage
|
|
||||||
|
|
||||||
```terraform
|
|
||||||
resource "gitea_org" "test_org" {
|
|
||||||
name = "test-org"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_user" "test" {
|
|
||||||
username = "test"
|
|
||||||
login_name = "test"
|
|
||||||
password = "Geheim1!"
|
|
||||||
email = "test@user.dev"
|
|
||||||
must_change_password = false
|
|
||||||
admin = true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
resource "gitea_team" "test_team" {
|
|
||||||
name = "Devs"
|
|
||||||
organisation = gitea_org.test_org.name
|
|
||||||
description = "Devs of Test Org"
|
|
||||||
permission = "write"
|
|
||||||
members = [gitea_user.test.username]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
resource "gitea_repository" "test" {
|
|
||||||
username = gitea_org.test_org.name
|
|
||||||
name = "test"
|
|
||||||
private = true
|
|
||||||
issue_labels = "Default"
|
|
||||||
license = "MIT"
|
|
||||||
gitignores = "Go"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_team" "test_team_restricted" {
|
|
||||||
name = "Restricted Devs"
|
|
||||||
organisation = gitea_org.test_org.name
|
|
||||||
description = "Restricted Devs of Test Org"
|
|
||||||
permission = "write"
|
|
||||||
members = [gitea_user.test.username]
|
|
||||||
include_all_repositories = false
|
|
||||||
repositories = [gitea_repository.test.name]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- schema generated by tfplugindocs -->
|
|
||||||
## Schema
|
|
||||||
|
|
||||||
### Required
|
|
||||||
|
|
||||||
- `name` (String) Name of the Team
|
|
||||||
- `organisation` (String) The organisation which this Team is part of.
|
|
||||||
|
|
||||||
### Optional
|
|
||||||
|
|
||||||
- `can_create_repos` (Boolean) Flag if the Teams members should be able to create Rpositories in the Organisation
|
|
||||||
- `description` (String) Description of the Team
|
|
||||||
- `include_all_repositories` (Boolean) Flag if the Teams members should have access to all Repositories in the Organisation
|
|
||||||
- `members` (List of String) List of Users that should be part of this team
|
|
||||||
- `permission` (String) Permissions associated with this Team
|
|
||||||
Can be `none`, `read`, `write`, `admin` or `owner`
|
|
||||||
- `repositories` (List of String) List of Repositories that should be part of this team
|
|
||||||
- `units` (String) List of types of Repositories that should be allowed to be created from Team members.
|
|
||||||
Can be `repo.code`, `repo.issues`, `repo.ext_issues`, `repo.wiki`, `repo.pulls`, `repo.releases`, `repo.projects` and/or `repo.ext_wiki`
|
|
||||||
|
|
||||||
### Read-Only
|
|
||||||
|
|
||||||
- `id` (String) The ID of this resource.
|
|
||||||
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
|||||||
---
|
|
||||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
|
||||||
page_title: "gitea_token Resource - terraform-provider-gitea"
|
|
||||||
subcategory: ""
|
|
||||||
description: |-
|
|
||||||
gitea_token manages gitea Access Tokens.
|
|
||||||
Due to upstream limitations (see https://gitea.com/gitea/go-sdk/issues/610) this resource
|
|
||||||
can only be used with username/password provider configuration.
|
|
||||||
WARNING:
|
|
||||||
Tokens will be stored in the terraform state!
|
|
||||||
---
|
|
||||||
|
|
||||||
# gitea_token (Resource)
|
|
||||||
|
|
||||||
`gitea_token` manages gitea Access Tokens.
|
|
||||||
|
|
||||||
Due to upstream limitations (see https://gitea.com/gitea/go-sdk/issues/610) this resource
|
|
||||||
can only be used with username/password provider configuration.
|
|
||||||
|
|
||||||
WARNING:
|
|
||||||
Tokens will be stored in the terraform state!
|
|
||||||
|
|
||||||
## Example Usage
|
|
||||||
|
|
||||||
```terraform
|
|
||||||
provider "gitea" {
|
|
||||||
base_url = var.gitea_url
|
|
||||||
# Token Auth can not be used with this resource
|
|
||||||
username = var.gitea_username
|
|
||||||
password = var.gitea_password
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_user" "test" {
|
|
||||||
username = "test"
|
|
||||||
login_name = "test"
|
|
||||||
password = "Geheim1!"
|
|
||||||
email = "test@user.dev"
|
|
||||||
must_change_password = false
|
|
||||||
admin = true
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_token" "test_token" {
|
|
||||||
username = resource.gitea_user.test.username
|
|
||||||
name = "test-token"
|
|
||||||
}
|
|
||||||
|
|
||||||
output "token" {
|
|
||||||
value = resource.gitea_token.test_token.token
|
|
||||||
sensitive = true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- schema generated by tfplugindocs -->
|
|
||||||
## Schema
|
|
||||||
|
|
||||||
### Required
|
|
||||||
|
|
||||||
- `name` (String) The name of the Access Token
|
|
||||||
- `username` (String) The owner of the Access Token
|
|
||||||
|
|
||||||
### Read-Only
|
|
||||||
|
|
||||||
- `id` (String) The ID of this resource.
|
|
||||||
- `last_eight` (String)
|
|
||||||
- `token` (String, Sensitive) The actual Access Token
|
|
||||||
|
|
||||||
|
|
1
examples/.gitignore
vendored
1
examples/.gitignore
vendored
@ -3,4 +3,3 @@
|
|||||||
terraform.tfstate
|
terraform.tfstate
|
||||||
terraform.tfstate.backup
|
terraform.tfstate.backup
|
||||||
*.tfvars
|
*.tfvars
|
||||||
id_ed25519
|
|
101
examples/main.tf
101
examples/main.tf
@ -12,14 +12,13 @@ resource "gitea_repository" "mirror" {
|
|||||||
name = "terraform-provider-gitea-mirror"
|
name = "terraform-provider-gitea-mirror"
|
||||||
description = "Mirror of Terraform Provider"
|
description = "Mirror of Terraform Provider"
|
||||||
mirror = true
|
mirror = true
|
||||||
migration_clone_address = "https://git.uploadfilter24.eu/lerentis/terraform-provider-gitea.git"
|
migration_clone_addresse = "https://git.uploadfilter24.eu/lerentis/terraform-provider-gitea.git"
|
||||||
migration_service = "gitea"
|
migration_service = "gitea"
|
||||||
migration_service_auth_token = var.gitea_mirror_token
|
migration_service_auth_token = var.gitea_mirror_token
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "gitea_org" "test_org" {
|
resource "gitea_org" "test_org" {
|
||||||
name = "test-org"
|
name = "test-org"
|
||||||
description = "test description"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "gitea_repository" "org_repo" {
|
resource "gitea_repository" "org_repo" {
|
||||||
@ -39,99 +38,3 @@ resource "gitea_user" "test" {
|
|||||||
must_change_password = false
|
must_change_password = false
|
||||||
admin = true
|
admin = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
resource "gitea_public_key" "test_user_key" {
|
|
||||||
title = "test"
|
|
||||||
key = file("${path.module}/resources/gitea_public_key/id_ed25519.pub")
|
|
||||||
read_only = true
|
|
||||||
username = gitea_user.test.username
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
resource "gitea_team" "test_team" {
|
|
||||||
name = "Devs"
|
|
||||||
organisation = gitea_org.test_org.name
|
|
||||||
description = "Devs of Test Org"
|
|
||||||
permission = "write"
|
|
||||||
members = [gitea_user.test.username]
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_team" "admin_team" {
|
|
||||||
name = "Admins"
|
|
||||||
organisation = gitea_org.test_org.name
|
|
||||||
description = "Admins of Test Org"
|
|
||||||
permission = "admin"
|
|
||||||
members = [data.gitea_user.me.username]
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_git_hook" "org_repo_pre_receive" {
|
|
||||||
name = "pre-receive"
|
|
||||||
user = gitea_org.test_org.name
|
|
||||||
repo = gitea_repository.org_repo.name
|
|
||||||
content = file("${path.module}/pre-receive.sh")
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_org" "org1" {
|
|
||||||
name = "org1"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_org" "org2" {
|
|
||||||
name = "org2"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_repository" "repo1_in_org1" {
|
|
||||||
username = gitea_org.org1.name
|
|
||||||
name = "repo1-in-org1"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_fork" "user_fork_of_repo1_in_org1" {
|
|
||||||
owner = gitea_org.org1.name
|
|
||||||
repo = gitea_repository.repo1_in_org1.name
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_fork" "org2_fork_of_repo1_in_org1" {
|
|
||||||
owner = gitea_org.org1.name
|
|
||||||
repo = gitea_repository.repo1_in_org1.name
|
|
||||||
organization = gitea_org.org2.name
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_token" "test_token" {
|
|
||||||
username = data.gitea_user.me.username
|
|
||||||
name = "test-token"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_repository" "test_existing_user" {
|
|
||||||
username = "testuser2"
|
|
||||||
name = "testExistingUser"
|
|
||||||
private = true
|
|
||||||
issue_labels = "Default"
|
|
||||||
license = "MIT"
|
|
||||||
gitignores = "Go"
|
|
||||||
}
|
|
||||||
|
|
||||||
//resource "gitea_repository" "test_bs_user" {
|
|
||||||
// username = "manualTest"
|
|
||||||
// name = "testBullshitUser"
|
|
||||||
// private = true
|
|
||||||
// issue_labels = "Default"
|
|
||||||
// license = "MIT"
|
|
||||||
// gitignores = "Go"
|
|
||||||
//}
|
|
||||||
|
|
||||||
output "token" {
|
|
||||||
value = resource.gitea_token.test_token.token
|
|
||||||
sensitive = true
|
|
||||||
}
|
|
||||||
|
|
||||||
data "gitea_repo" "org_repos" {
|
|
||||||
name = each.key
|
|
||||||
username = gitea_org.org1.name
|
|
||||||
for_each = {
|
|
||||||
for repo in resource.gitea_org.org1.repos : repo => repo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
output "repos" {
|
|
||||||
value = data.gitea_repo.org_repos["repo1-in-org1"].clone_url
|
|
||||||
}
|
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
while read oldrev newrev refname
|
|
||||||
do
|
|
||||||
branch=$(git rev-parse --symbolic --abbrev-ref $refname)
|
|
||||||
if [ "master" = "$branch" ]; then
|
|
||||||
echo "wrong branch"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
@ -2,14 +2,12 @@ terraform {
|
|||||||
required_providers {
|
required_providers {
|
||||||
gitea = {
|
gitea = {
|
||||||
source = "terraform.local/lerentis/gitea"
|
source = "terraform.local/lerentis/gitea"
|
||||||
version = "0.16.0"
|
version = "0.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provider "gitea" {
|
provider "gitea" {
|
||||||
base_url = var.gitea_url
|
base_url = var.gitea_url
|
||||||
username = "lerentis"
|
token = var.gitea_token
|
||||||
password = var.gitea_password
|
|
||||||
#token = var.gitea_token
|
|
||||||
}
|
}
|
@ -2,7 +2,7 @@ terraform {
|
|||||||
required_providers {
|
required_providers {
|
||||||
gitea = {
|
gitea = {
|
||||||
source = "Lerentis/gitea"
|
source = "Lerentis/gitea"
|
||||||
version = "0.16.0"
|
version = "0.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
resource "gitea_org" "org1" {
|
|
||||||
name = "org1"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_org" "org2" {
|
|
||||||
name = "org2"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_repository" "repo1_in_org1" {
|
|
||||||
username = gitea_org.org1.name
|
|
||||||
name = "repo1-in-org1"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_fork" "user_fork_of_repo1_in_org1" {
|
|
||||||
owner = gitea_org.org1.name
|
|
||||||
repo = gitea_repository.repo1_in_org1.name
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_fork" "org2_fork_of_repo1_in_org1" {
|
|
||||||
owner = gitea_org.org1.name
|
|
||||||
repo = gitea_repository.repo1_in_org1.name
|
|
||||||
organization = gitea_org.org2.name
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
while read oldrev newrev refname
|
|
||||||
do
|
|
||||||
branch=$(git rev-parse --symbolic --abbrev-ref $refname)
|
|
||||||
if [ "master" = "$branch" ]; then
|
|
||||||
# Do something
|
|
||||||
fi
|
|
||||||
done
|
|
@ -1,15 +0,0 @@
|
|||||||
resource "gitea_org" "test_org" {
|
|
||||||
name = "test-org"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_repository" "org_repo" {
|
|
||||||
username = gitea_org.test_org.name
|
|
||||||
name = "org-test-repo"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_git_hook" "org_repo_post_receive" {
|
|
||||||
name = "post-receive"
|
|
||||||
user = gitea_org.test_org.name
|
|
||||||
repo = gitea_repository.org_repo.name
|
|
||||||
content = file("${path.module}/post-receive.sh")
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINn6hAP48oKz6MVWjYvn0fne2YeaOv/zC6zuvFXlJKf2 test@dev.local
|
|
@ -1,14 +0,0 @@
|
|||||||
resource "gitea_user" "test" {
|
|
||||||
username = "test"
|
|
||||||
login_name = "test"
|
|
||||||
password = "Geheim1!"
|
|
||||||
email = "test@user.dev"
|
|
||||||
must_change_password = false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
resource "gitea_public_key" "test_user_key" {
|
|
||||||
title = "test"
|
|
||||||
key = file("${path.module}/id_ed25519.pub")
|
|
||||||
username = gitea_user.test.username
|
|
||||||
}
|
|
@ -16,13 +16,3 @@ resource "gitea_repository" "mirror" {
|
|||||||
migration_service = "gitea"
|
migration_service = "gitea"
|
||||||
migration_service_auth_token = var.gitea_mirror_token
|
migration_service_auth_token = var.gitea_mirror_token
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "gitea_repository" "clone" {
|
|
||||||
username = "lerentis"
|
|
||||||
name = "terraform-provider-gitea-clone"
|
|
||||||
description = "Clone of Terraform Provider"
|
|
||||||
mirror = false
|
|
||||||
migration_clone_address = "https://git.uploadfilter24.eu/lerentis/terraform-provider-gitea.git"
|
|
||||||
migration_service = "gitea"
|
|
||||||
migration_service_auth_token = var.gitea_clone_token
|
|
||||||
}
|
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
terraform {
|
|
||||||
required_providers {
|
|
||||||
tls = {
|
|
||||||
source = "hashicorp/tls"
|
|
||||||
version = "4.0.4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "tls_private_key" "example" {
|
|
||||||
type = "RSA"
|
|
||||||
rsa_bits = 4096
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_repository" "example" {
|
|
||||||
name = "example"
|
|
||||||
private = true
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_repository_key" "example" {
|
|
||||||
repository = gitea_repository.example.id
|
|
||||||
title = "Example Deploy Key"
|
|
||||||
read_only = true
|
|
||||||
key = tls_private_key.example.public_key_openssh
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
resource "gitea_org" "test_org" {
|
|
||||||
name = "test-org"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_user" "test" {
|
|
||||||
username = "test"
|
|
||||||
login_name = "test"
|
|
||||||
password = "Geheim1!"
|
|
||||||
email = "test@user.dev"
|
|
||||||
must_change_password = false
|
|
||||||
admin = true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
resource "gitea_team" "test_team" {
|
|
||||||
name = "Devs"
|
|
||||||
organisation = gitea_org.test_org.name
|
|
||||||
description = "Devs of Test Org"
|
|
||||||
permission = "write"
|
|
||||||
members = [gitea_user.test.username]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
resource "gitea_repository" "test" {
|
|
||||||
username = gitea_org.test_org.name
|
|
||||||
name = "test"
|
|
||||||
private = true
|
|
||||||
issue_labels = "Default"
|
|
||||||
license = "MIT"
|
|
||||||
gitignores = "Go"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_team" "test_team_restricted" {
|
|
||||||
name = "Restricted Devs"
|
|
||||||
organisation = gitea_org.test_org.name
|
|
||||||
description = "Restricted Devs of Test Org"
|
|
||||||
permission = "write"
|
|
||||||
members = [gitea_user.test.username]
|
|
||||||
include_all_repositories = false
|
|
||||||
repositories = [gitea_repository.test.name]
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
provider "gitea" {
|
|
||||||
base_url = var.gitea_url
|
|
||||||
# Token Auth can not be used with this resource
|
|
||||||
username = var.gitea_username
|
|
||||||
password = var.gitea_password
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_user" "test" {
|
|
||||||
username = "test"
|
|
||||||
login_name = "test"
|
|
||||||
password = "Geheim1!"
|
|
||||||
email = "test@user.dev"
|
|
||||||
must_change_password = false
|
|
||||||
admin = true
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "gitea_token" "test_token" {
|
|
||||||
username = resource.gitea_user.test.username
|
|
||||||
name = "test-token"
|
|
||||||
}
|
|
||||||
|
|
||||||
output "token" {
|
|
||||||
value = resource.gitea_token.test_token.token
|
|
||||||
sensitive = true
|
|
||||||
}
|
|
@ -9,7 +9,3 @@ variable "gitea_token" {
|
|||||||
variable "gitea_mirror_token" {
|
variable "gitea_mirror_token" {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "gitea_password" {
|
|
||||||
|
|
||||||
}
|
|
@ -6,10 +6,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
"code.gitea.io/sdk/gitea"
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging"
|
"github.com/hashicorp/terraform-plugin-sdk/helper/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config is per-provider, specifies where to connect to gitea
|
// Config is per-provider, specifies where to connect to gitea
|
||||||
@ -29,7 +28,8 @@ func (c *Config) Client() (interface{}, error) {
|
|||||||
return nil, fmt.Errorf("either a token or a username needs to be used")
|
return nil, fmt.Errorf("either a token or a username needs to be used")
|
||||||
}
|
}
|
||||||
// Configure TLS/SSL
|
// Configure TLS/SSL
|
||||||
var tlsConfig tls.Config
|
tlsConfig := &tls.Config{}
|
||||||
|
|
||||||
// If a CACertFile has been specified, use that for cert validation
|
// If a CACertFile has been specified, use that for cert validation
|
||||||
if c.CACertFile != "" {
|
if c.CACertFile != "" {
|
||||||
caCert, err := ioutil.ReadFile(c.CACertFile)
|
caCert, err := ioutil.ReadFile(c.CACertFile)
|
||||||
@ -43,12 +43,13 @@ func (c *Config) Client() (interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If configured as insecure, turn off SSL verification
|
// If configured as insecure, turn off SSL verification
|
||||||
tlsConfig.InsecureSkipVerify = c.Insecure
|
if c.Insecure {
|
||||||
|
tlsConfig.InsecureSkipVerify = true
|
||||||
|
}
|
||||||
|
|
||||||
t := http.DefaultTransport.(*http.Transport).Clone()
|
t := http.DefaultTransport.(*http.Transport).Clone()
|
||||||
t.TLSClientConfig = &tlsConfig
|
t.TLSClientConfig = tlsConfig
|
||||||
t.MaxIdleConnsPerHost = 100
|
t.MaxIdleConnsPerHost = 100
|
||||||
t.TLSHandshakeTimeout = 10 * time.Second
|
|
||||||
|
|
||||||
httpClient := &http.Client{
|
httpClient := &http.Client{
|
||||||
Transport: logging.NewTransport("Gitea", t),
|
Transport: logging.NewTransport("Gitea", t),
|
||||||
@ -59,23 +60,16 @@ func (c *Config) Client() (interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var client *gitea.Client
|
var client *gitea.Client
|
||||||
var err error
|
|
||||||
if c.Token != "" {
|
if c.Token != "" {
|
||||||
client, err = gitea.NewClient(c.BaseURL, gitea.SetToken(c.Token), gitea.SetHTTPClient(httpClient))
|
client, _ = gitea.NewClient(c.BaseURL, gitea.SetToken(c.Token), gitea.SetHTTPClient(httpClient))
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Username != "" {
|
if c.Username != "" {
|
||||||
client, err = gitea.NewClient(c.BaseURL, gitea.SetBasicAuth(c.Username, c.Password), gitea.SetHTTPClient(httpClient))
|
client, _ = gitea.NewClient(c.BaseURL, gitea.SetBasicAuth(c.Username, c.Password), gitea.SetHTTPClient(httpClient))
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test the credentials by checking we can get information about the authenticated user.
|
// Test the credentials by checking we can get information about the authenticated user.
|
||||||
_, _, err = client.GetMyUserInfo()
|
_, _, err := client.GetMyUserInfo()
|
||||||
|
|
||||||
return client, err
|
return client, err
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
"code.gitea.io/sdk/gitea"
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
func dataSourceGiteaOrg() *schema.Resource {
|
func dataSourceGiteaOrg() *schema.Resource {
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
"code.gitea.io/sdk/gitea"
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
func dataSourceGiteaRepo() *schema.Resource {
|
func dataSourceGiteaRepo() *schema.Resource {
|
||||||
@ -116,7 +116,7 @@ func dataSourceGiteaRepoRead(d *schema.ResourceData, meta interface{}) error {
|
|||||||
}
|
}
|
||||||
username := strings.ToLower(usernameData.(string))
|
username := strings.ToLower(usernameData.(string))
|
||||||
|
|
||||||
nameData, nameOk := d.GetOk("name")
|
nameData, nameOk := d.GetOk("username")
|
||||||
if !nameOk {
|
if !nameOk {
|
||||||
return fmt.Errorf("name of repo must be passed")
|
return fmt.Errorf("name of repo must be passed")
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
"code.gitea.io/sdk/gitea"
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
func dataSourceGiteaUser() *schema.Resource {
|
func dataSourceGiteaUser() *schema.Resource {
|
||||||
|
@ -4,8 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
|
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
|
"github.com/hashicorp/terraform-plugin-sdk/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAccDataSourceGiteaUser_basic(t *testing.T) {
|
func TestAccDataSourceGiteaUser_basic(t *testing.T) {
|
||||||
|
@ -4,11 +4,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Provider returns a terraform.ResourceProvider.
|
// Provider returns a terraform.ResourceProvider.
|
||||||
func Provider() *schema.Provider {
|
func Provider() terraform.ResourceProvider {
|
||||||
|
|
||||||
// The actual provider
|
// The actual provider
|
||||||
return &schema.Provider{
|
return &schema.Provider{
|
||||||
@ -73,17 +74,11 @@ func Provider() *schema.Provider {
|
|||||||
|
|
||||||
ResourcesMap: map[string]*schema.Resource{
|
ResourcesMap: map[string]*schema.Resource{
|
||||||
"gitea_org": resourceGiteaOrg(),
|
"gitea_org": resourceGiteaOrg(),
|
||||||
// "gitea_team": resourceGiteaTeam(),
|
// "gitea_team": resourceGiteaTeam(),
|
||||||
// "gitea_repo": resourceGiteaRepo(),
|
// "gitea_repo": resourceGiteaRepo(),
|
||||||
"gitea_user": resourceGiteaUser(),
|
"gitea_user": resourceGiteaUser(),
|
||||||
"gitea_oauth2_app": resourceGiteaOauthApp(),
|
"gitea_oauth2_app": resourceGiteaOauthApp(),
|
||||||
"gitea_repository": resourceGiteaRepository(),
|
"gitea_repository": resourceGiteaRepository(),
|
||||||
"gitea_fork": resourceGiteaFork(),
|
|
||||||
"gitea_public_key": resourceGiteaPublicKey(),
|
|
||||||
"gitea_team": resourceGiteaTeam(),
|
|
||||||
"gitea_git_hook": resourceGiteaGitHook(),
|
|
||||||
"gitea_token": resourceGiteaToken(),
|
|
||||||
"gitea_repository_key": resourceGiteaRepositoryKey(),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
ConfigureFunc: providerConfigure,
|
ConfigureFunc: providerConfigure,
|
||||||
@ -121,8 +116,5 @@ func validateAPIURLVersion(value interface{}, key string) (ws []string, es []err
|
|||||||
if strings.HasSuffix(v, "/api/v1") || strings.HasSuffix(v, "/api/v1/") {
|
if strings.HasSuffix(v, "/api/v1") || strings.HasSuffix(v, "/api/v1/") {
|
||||||
es = append(es, fmt.Errorf("terraform-gitea-provider base URL format is incorrect; Please leave out API Path %s", v))
|
es = append(es, fmt.Errorf("terraform-gitea-provider base URL format is incorrect; Please leave out API Path %s", v))
|
||||||
}
|
}
|
||||||
if strings.Contains(v, "localhost") && strings.Contains(v, ".") {
|
|
||||||
es = append(es, fmt.Errorf("terraform-gitea-provider base URL violates RFC 2606; Please do not define a subdomain for localhost!"))
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -4,28 +4,30 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testAccProviders map[string]*schema.Provider
|
var testAccProviders map[string]terraform.ResourceProvider
|
||||||
var testAccProvider *schema.Provider
|
var testAccProvider *schema.Provider
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
testAccProvider = Provider()
|
testAccProvider = Provider().(*schema.Provider)
|
||||||
testAccProviders = map[string]*schema.Provider{
|
testAccProviders = map[string]terraform.ResourceProvider{
|
||||||
"gitea": testAccProvider,
|
"gitea": testAccProvider,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProvider(t *testing.T) {
|
func TestProvider(t *testing.T) {
|
||||||
if err := Provider().InternalValidate(); err != nil {
|
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProvider_impl(t *testing.T) {
|
func TestProvider_impl(t *testing.T) {
|
||||||
var _ *schema.Provider = Provider()
|
var _ terraform.ResourceProvider = Provider()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAccPreCheck(t *testing.T) {
|
func testAccPreCheck(t *testing.T) {
|
||||||
if v := os.Getenv("GITEA_TOKEN"); v == "" {
|
if v := os.Getenv("GITEA_TOKEN"); v == "" {
|
||||||
t.Fatal("GITEA_TOKEN must be set for acceptance tests")
|
t.Fatal("GITEA_TOKEN must be set for acceptance tests")
|
||||||
|
@ -1,127 +0,0 @@
|
|||||||
package gitea
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
forkOwner string = "owner"
|
|
||||||
forkRepo string = "repo"
|
|
||||||
forkOrganization string = "organization"
|
|
||||||
)
|
|
||||||
|
|
||||||
func resourceForkCreate(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
var opts gitea.CreateForkOption
|
|
||||||
var org string
|
|
||||||
org = d.Get(forkOrganization).(string)
|
|
||||||
if org != "" {
|
|
||||||
opts.Organization = &org
|
|
||||||
}
|
|
||||||
|
|
||||||
repo, _, err := client.CreateFork(d.Get(forkOwner).(string),
|
|
||||||
d.Get(forkRepo).(string),
|
|
||||||
opts)
|
|
||||||
if err == nil {
|
|
||||||
err = setForkResourceData(repo, d)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceForkRead(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
id, err := strconv.ParseInt(d.Id(), 10, 64)
|
|
||||||
var resp *gitea.Response
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
repo, resp, err := client.GetRepoByID(id)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if resp.StatusCode == 404 {
|
|
||||||
d.SetId("")
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = setForkResourceData(repo, d)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceForkDelete(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
id, err := strconv.ParseInt(d.Id(), 10, 64)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
repo, _, err := client.GetRepoByID(id)
|
|
||||||
var resp *gitea.Response
|
|
||||||
|
|
||||||
resp, err = client.DeleteRepo(repo.Owner.UserName, repo.Name)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if resp.StatusCode == 404 {
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func setForkResourceData(repo *gitea.Repository, d *schema.ResourceData) (err error) {
|
|
||||||
|
|
||||||
d.SetId(fmt.Sprintf("%d", repo.ID))
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceGiteaFork() *schema.Resource {
|
|
||||||
return &schema.Resource{
|
|
||||||
Read: resourceForkRead,
|
|
||||||
Create: resourceForkCreate,
|
|
||||||
Delete: resourceForkDelete,
|
|
||||||
Importer: &schema.ResourceImporter{
|
|
||||||
StateContext: schema.ImportStatePassthroughContext,
|
|
||||||
},
|
|
||||||
Schema: map[string]*schema.Schema{
|
|
||||||
"owner": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
ForceNew: true,
|
|
||||||
Description: "The owner or owning organization of the repository to fork",
|
|
||||||
},
|
|
||||||
"repo": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
ForceNew: true,
|
|
||||||
Description: "The name of the repository to fork",
|
|
||||||
},
|
|
||||||
"organization": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: false,
|
|
||||||
Optional: true,
|
|
||||||
ForceNew: true,
|
|
||||||
Description: "The organization that owns the forked repo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Description: "`gitea_fork` manages repository fork to the current user or an organisation\n" +
|
|
||||||
"Forking a repository to a dedicated user is currently unsupported\n" +
|
|
||||||
"Creating a fork using this resource without an organisation will create the fork in the executors name",
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,120 +0,0 @@
|
|||||||
package gitea
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
GitHookUser string = "user"
|
|
||||||
GitHookRepo string = "repo"
|
|
||||||
GitHookName string = "name"
|
|
||||||
GitHookContent string = "content"
|
|
||||||
)
|
|
||||||
|
|
||||||
func resourceGitHookRead(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
user := d.Get(GitHookUser).(string)
|
|
||||||
repo := d.Get(GitHookRepo).(string)
|
|
||||||
name := d.Get(GitHookName).(string)
|
|
||||||
|
|
||||||
gitHook, _, err := client.GetRepoGitHook(user, repo, name)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = setGitHookResourceData(user, repo, gitHook, d)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceGitHookUpdate(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
user := d.Get(GitHookUser).(string)
|
|
||||||
repo := d.Get(GitHookRepo).(string)
|
|
||||||
name := d.Get(GitHookName).(string)
|
|
||||||
|
|
||||||
opts := gitea.EditGitHookOption{
|
|
||||||
Content: d.Get(GitHookContent).(string),
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = client.EditRepoGitHook(user, repo, name, opts)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get gitHook ourselves, EditRepoGitHook does not return it
|
|
||||||
gitHook, _, err := client.GetRepoGitHook(user, repo, name)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = setGitHookResourceData(user, repo, gitHook, d)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceGitHookDelete(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
user := d.Get(GitHookUser).(string)
|
|
||||||
repo := d.Get(GitHookRepo).(string)
|
|
||||||
name := d.Get(GitHookName).(string)
|
|
||||||
|
|
||||||
_, err = client.DeleteRepoGitHook(user, repo, name)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func setGitHookResourceData(user string, repo string, gitHook *gitea.GitHook, d *schema.ResourceData) (err error) {
|
|
||||||
d.SetId(fmt.Sprintf("%s/%s/%s", user, repo, gitHook.Name))
|
|
||||||
d.Set(GitHookUser, user)
|
|
||||||
d.Set(GitHookRepo, repo)
|
|
||||||
d.Set(GitHookName, gitHook.Name)
|
|
||||||
d.Set(GitHookContent, gitHook.Content)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceGiteaGitHook() *schema.Resource {
|
|
||||||
return &schema.Resource{
|
|
||||||
Read: resourceGitHookRead,
|
|
||||||
Create: resourceGitHookUpdate, // All hooks already exist, just empty and disabled
|
|
||||||
Update: resourceGitHookUpdate,
|
|
||||||
Delete: resourceGitHookDelete,
|
|
||||||
Schema: map[string]*schema.Schema{
|
|
||||||
"name": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
Description: "Name of the git hook to configure",
|
|
||||||
},
|
|
||||||
"repo": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
Description: "The repository that this hook belongs too.",
|
|
||||||
},
|
|
||||||
"user": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
Description: "The user (or organisation) owning the repo this hook belongs too",
|
|
||||||
},
|
|
||||||
"content": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
Description: "Content of the git hook",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Description: "`gitea_git_hook` manages git hooks on a repository.\n" +
|
|
||||||
"import is currently not supported\n\n" +
|
|
||||||
"WARNING: using this resource requires to enable server side hooks" +
|
|
||||||
"which are known to cause [security issues](https://github.com/go-gitea/gitea/pull/13058)!\n\n" +
|
|
||||||
"if you want to procede, you need to enable server side hooks as stated" +
|
|
||||||
" [here](https://docs.gitea.io/en-us/config-cheat-sheet/#security-security)",
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,15 +4,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
"code.gitea.io/sdk/gitea"
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
oauth2KeyName string = "name"
|
oauth2KeyName string = "name"
|
||||||
oauth2KeyConfidentialClient string = "confidential_client"
|
oauth2KeyRedirectURIs string = "redirect_uris"
|
||||||
oauth2KeyRedirectURIs string = "redirect_uris"
|
oauth2KeyClientId string = "client_id"
|
||||||
oauth2KeyClientId string = "client_id"
|
oauth2KeyClientSecret string = "client_secret"
|
||||||
oauth2KeyClientSecret string = "client_secret"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func resourceGiteaOauthApp() *schema.Resource {
|
func resourceGiteaOauthApp() *schema.Resource {
|
||||||
@ -38,12 +37,6 @@ func resourceGiteaOauthApp() *schema.Resource {
|
|||||||
},
|
},
|
||||||
Description: "Accepted redirect URIs",
|
Description: "Accepted redirect URIs",
|
||||||
},
|
},
|
||||||
oauth2KeyConfidentialClient: {
|
|
||||||
Type: schema.TypeBool,
|
|
||||||
Optional: true,
|
|
||||||
Default: false,
|
|
||||||
Description: "If set to false, it will be a public client (PKCE will be required)",
|
|
||||||
},
|
|
||||||
oauth2KeyClientId: {
|
oauth2KeyClientId: {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
@ -96,16 +89,9 @@ func resourceOauth2AppUpcreate(d *schema.ResourceData, meta interface{}) (err er
|
|||||||
return fmt.Errorf("attribute %s must be set and must be a string", oauth2KeyName)
|
return fmt.Errorf("attribute %s must be set and must be a string", oauth2KeyName)
|
||||||
}
|
}
|
||||||
|
|
||||||
confidentialClient, confidentialClientOk := d.Get(oauth2KeyConfidentialClient).(bool)
|
|
||||||
|
|
||||||
if !confidentialClientOk {
|
|
||||||
return fmt.Errorf("attribute %s must be set and must be a bool", oauth2KeyConfidentialClient)
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := gitea.CreateOauth2Option{
|
opts := gitea.CreateOauth2Option{
|
||||||
Name: name,
|
Name: name,
|
||||||
ConfidentialClient: confidentialClient,
|
RedirectURIs: redirectURIs,
|
||||||
RedirectURIs: redirectURIs,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var oauth2 *gitea.Oauth2
|
var oauth2 *gitea.Oauth2
|
||||||
@ -113,7 +99,7 @@ func resourceOauth2AppUpcreate(d *schema.ResourceData, meta interface{}) (err er
|
|||||||
if d.IsNewResource() {
|
if d.IsNewResource() {
|
||||||
oauth2, _, err = client.CreateOauth2(opts)
|
oauth2, _, err = client.CreateOauth2(opts)
|
||||||
} else {
|
} else {
|
||||||
oauth2, err = searchOauth2AppByClientId(client, d.Id())
|
oauth2, err := searchOauth2AppByClientId(client, d.Id())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -190,10 +176,9 @@ func setOAuth2ResourceData(app *gitea.Oauth2, d *schema.ResourceData) (err error
|
|||||||
d.SetId(app.ClientID)
|
d.SetId(app.ClientID)
|
||||||
|
|
||||||
for k, v := range map[string]interface{}{
|
for k, v := range map[string]interface{}{
|
||||||
oauth2KeyName: app.Name,
|
oauth2KeyName: app.Name,
|
||||||
oauth2KeyConfidentialClient: app.ConfidentialClient,
|
oauth2KeyRedirectURIs: schema.NewSet(schema.HashString, CollapseStringList(app.RedirectURIs)),
|
||||||
oauth2KeyRedirectURIs: schema.NewSet(schema.HashString, CollapseStringList(app.RedirectURIs)),
|
oauth2KeyClientId: app.ClientID,
|
||||||
oauth2KeyClientId: app.ClientID,
|
|
||||||
} {
|
} {
|
||||||
err = d.Set(k, v)
|
err = d.Set(k, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -2,10 +2,9 @@ package gitea
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
"code.gitea.io/sdk/gitea"
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -16,81 +15,26 @@ const (
|
|||||||
orgLocation string = "location"
|
orgLocation string = "location"
|
||||||
orgVisibility string = "visibility"
|
orgVisibility string = "visibility"
|
||||||
RepoAdminChangeTeamAccess string = "repo_admin_change_team_access"
|
RepoAdminChangeTeamAccess string = "repo_admin_change_team_access"
|
||||||
orgRepos string = "org_repos"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// might come in handy if we want to stick to numeric IDs
|
|
||||||
func searchOrgByClientId(c *gitea.Client, id int64) (res *gitea.Organization, err error) {
|
|
||||||
|
|
||||||
page := 1
|
|
||||||
|
|
||||||
for {
|
|
||||||
orgs, _, err := c.AdminListOrgs(gitea.AdminListOrgsOptions{
|
|
||||||
ListOptions: gitea.ListOptions{
|
|
||||||
Page: page,
|
|
||||||
PageSize: 50,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(orgs) == 0 {
|
|
||||||
return nil, fmt.Errorf("Organisation with ID %d could not be found", id)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, org := range orgs {
|
|
||||||
if org.ID == id {
|
|
||||||
return org, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
page += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAllOrgRepos(c *gitea.Client, orgName string) (repos []string, err error) {
|
|
||||||
page := 1
|
|
||||||
|
|
||||||
for {
|
|
||||||
repoBuffer, _, err := c.ListOrgRepos(orgName, gitea.ListOrgReposOptions{
|
|
||||||
ListOptions: gitea.ListOptions{
|
|
||||||
Page: page,
|
|
||||||
PageSize: 50,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(repoBuffer) == 0 {
|
|
||||||
return repos, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, repo := range repoBuffer {
|
|
||||||
repos = append(repos, repo.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
page += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceOrgRead(d *schema.ResourceData, meta interface{}) (err error) {
|
func resourceOrgRead(d *schema.ResourceData, meta interface{}) (err error) {
|
||||||
client := meta.(*gitea.Client)
|
client := meta.(*gitea.Client)
|
||||||
|
|
||||||
var org *gitea.Organization
|
var org *gitea.Organization
|
||||||
|
var resp *gitea.Response
|
||||||
|
|
||||||
id, err := strconv.ParseInt(d.Id(), 10, 64)
|
org, resp, err = client.GetOrg(d.Get(orgName).(string))
|
||||||
|
|
||||||
org, err = searchOrgByClientId(client, id)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.SetId("")
|
if resp.StatusCode == 404 {
|
||||||
return nil
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repos, _ := getAllOrgRepos(client, org.UserName)
|
err = setOrgResourceData(org, d)
|
||||||
err = setOrgResourceData(org, d, &repos)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -113,8 +57,7 @@ func resourceOrgCreate(d *schema.ResourceData, meta interface{}) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
repos, _ := getAllOrgRepos(client, org.UserName)
|
err = setOrgResourceData(org, d)
|
||||||
err = setOrgResourceData(org, d, &repos)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -147,8 +90,7 @@ func resourceOrgUpdate(d *schema.ResourceData, meta interface{}) (err error) {
|
|||||||
|
|
||||||
org, resp, err = client.GetOrg(d.Get(orgName).(string))
|
org, resp, err = client.GetOrg(d.Get(orgName).(string))
|
||||||
|
|
||||||
repos, _ := getAllOrgRepos(client, org.UserName)
|
err = setOrgResourceData(org, d)
|
||||||
err = setOrgResourceData(org, d, &repos)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -171,7 +113,7 @@ func resourceOrgDelete(d *schema.ResourceData, meta interface{}) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func setOrgResourceData(org *gitea.Organization, d *schema.ResourceData, repos *[]string) (err error) {
|
func setOrgResourceData(org *gitea.Organization, d *schema.ResourceData) (err error) {
|
||||||
d.SetId(fmt.Sprintf("%d", org.ID))
|
d.SetId(fmt.Sprintf("%d", org.ID))
|
||||||
d.Set("name", org.UserName)
|
d.Set("name", org.UserName)
|
||||||
d.Set("full_name", org.FullName)
|
d.Set("full_name", org.FullName)
|
||||||
@ -180,7 +122,6 @@ func setOrgResourceData(org *gitea.Organization, d *schema.ResourceData, repos *
|
|||||||
d.Set("website", org.Website)
|
d.Set("website", org.Website)
|
||||||
d.Set("location", org.Location)
|
d.Set("location", org.Location)
|
||||||
d.Set("visibility", org.Visibility)
|
d.Set("visibility", org.Visibility)
|
||||||
d.Set("repos", repos)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -192,7 +133,7 @@ func resourceGiteaOrg() *schema.Resource {
|
|||||||
Update: resourceOrgUpdate,
|
Update: resourceOrgUpdate,
|
||||||
Delete: resourceOrgDelete,
|
Delete: resourceOrgDelete,
|
||||||
Importer: &schema.ResourceImporter{
|
Importer: &schema.ResourceImporter{
|
||||||
StateContext: schema.ImportStatePassthroughContext,
|
State: schema.ImportStatePassthrough,
|
||||||
},
|
},
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: map[string]*schema.Schema{
|
||||||
"name": {
|
"name": {
|
||||||
@ -242,13 +183,6 @@ func resourceGiteaOrg() *schema.Resource {
|
|||||||
Default: "public",
|
Default: "public",
|
||||||
Description: "Flag is this organisation should be publicly visible or not.",
|
Description: "Flag is this organisation should be publicly visible or not.",
|
||||||
},
|
},
|
||||||
"repos": {
|
|
||||||
Type: schema.TypeList,
|
|
||||||
Required: false,
|
|
||||||
Computed: true,
|
|
||||||
Description: "List of all Repositories that are part of this organisation",
|
|
||||||
Elem: &schema.Schema{Type: schema.TypeString},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Description: "`gitea_org` manages a gitea organisation.\n\n" +
|
Description: "`gitea_org` manages a gitea organisation.\n\n" +
|
||||||
"Organisations are a way to group repositories and abstract permission management in a gitea instance.",
|
"Organisations are a way to group repositories and abstract permission management in a gitea instance.",
|
||||||
|
@ -1,155 +0,0 @@
|
|||||||
package gitea
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
PublicKeyUser string = "username"
|
|
||||||
PublicKey string = "key"
|
|
||||||
PublicKeyReadOnlyFlag string = "read_only"
|
|
||||||
PublicKeyTitle string = "title"
|
|
||||||
PublicKeyId string = "id"
|
|
||||||
PublicKeyFingerprint string = "fingerprint"
|
|
||||||
PublicKeyCreated string = "created"
|
|
||||||
PublicKeyType string = "type"
|
|
||||||
)
|
|
||||||
|
|
||||||
func resourcePublicKeyRead(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
id, err := strconv.ParseInt(d.Id(), 10, 64)
|
|
||||||
|
|
||||||
var resp *gitea.Response
|
|
||||||
var pubKey *gitea.PublicKey
|
|
||||||
|
|
||||||
pubKey, resp, err = client.GetPublicKey(id)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if resp.StatusCode == 404 {
|
|
||||||
d.SetId("")
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = setPublicKeyResourceData(pubKey, d)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourcePublicKeyCreate(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
var pubKey *gitea.PublicKey
|
|
||||||
|
|
||||||
opts := gitea.CreateKeyOption{
|
|
||||||
Title: d.Get(PublicKeyTitle).(string),
|
|
||||||
Key: d.Get(PublicKey).(string),
|
|
||||||
ReadOnly: d.Get(PublicKeyReadOnlyFlag).(bool),
|
|
||||||
}
|
|
||||||
|
|
||||||
pubKey, _, err = client.AdminCreateUserPublicKey(d.Get(PublicKeyUser).(string), opts)
|
|
||||||
|
|
||||||
err = setPublicKeyResourceData(pubKey, d)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourcePublicKeyUpdate(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
// update = recreate
|
|
||||||
resourcePublicKeyDelete(d, meta)
|
|
||||||
resourcePublicKeyCreate(d, meta)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourcePublicKeyDelete(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
id, err := strconv.ParseInt(d.Id(), 10, 64)
|
|
||||||
|
|
||||||
var resp *gitea.Response
|
|
||||||
|
|
||||||
resp, err = client.AdminDeleteUserPublicKey(d.Get(PublicKeyUser).(string), int(id))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if resp.StatusCode == 404 {
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func setPublicKeyResourceData(pubKey *gitea.PublicKey, d *schema.ResourceData) (err error) {
|
|
||||||
d.SetId(fmt.Sprintf("%d", pubKey.ID))
|
|
||||||
d.Set(PublicKeyUser, d.Get(PublicKeyUser).(string))
|
|
||||||
d.Set(PublicKey, d.Get(PublicKey).(string))
|
|
||||||
d.Set(PublicKeyTitle, pubKey.Title)
|
|
||||||
d.Set(PublicKeyReadOnlyFlag, d.Get(PublicKeyReadOnlyFlag).(bool))
|
|
||||||
d.Set(PublicKeyCreated, pubKey.Created)
|
|
||||||
d.Set(PublicKeyFingerprint, pubKey.Fingerprint)
|
|
||||||
d.Set(PublicKeyType, pubKey.KeyType)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceGiteaPublicKey() *schema.Resource {
|
|
||||||
return &schema.Resource{
|
|
||||||
Read: resourcePublicKeyRead,
|
|
||||||
Create: resourcePublicKeyCreate,
|
|
||||||
Update: resourcePublicKeyUpdate,
|
|
||||||
Delete: resourcePublicKeyDelete,
|
|
||||||
Importer: &schema.ResourceImporter{
|
|
||||||
State: schema.ImportStatePassthrough,
|
|
||||||
},
|
|
||||||
Schema: map[string]*schema.Schema{
|
|
||||||
"title": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
ForceNew: true,
|
|
||||||
Description: "Title of the key to add",
|
|
||||||
},
|
|
||||||
"key": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
ForceNew: true,
|
|
||||||
Sensitive: true,
|
|
||||||
Description: "An armored SSH key to add",
|
|
||||||
},
|
|
||||||
"read_only": {
|
|
||||||
Type: schema.TypeBool,
|
|
||||||
Required: false,
|
|
||||||
Optional: true,
|
|
||||||
Default: false,
|
|
||||||
Description: "Describe if the key has only read access or read/write",
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
Optional: false,
|
|
||||||
ForceNew: true,
|
|
||||||
Description: "User to associate with the added key",
|
|
||||||
},
|
|
||||||
"fingerprint": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
"created": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Description: "`gitea_public_key` manages ssh key that are associated with users.",
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +1,11 @@
|
|||||||
package gitea
|
package gitea
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
"code.gitea.io/sdk/gitea"
|
||||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -38,8 +34,7 @@ const (
|
|||||||
repoAllowManualMerge string = "allow_manual_merge"
|
repoAllowManualMerge string = "allow_manual_merge"
|
||||||
repoAutodetectManualMerge string = "autodetect_manual_merge"
|
repoAutodetectManualMerge string = "autodetect_manual_merge"
|
||||||
repoMirror string = "mirror"
|
repoMirror string = "mirror"
|
||||||
migrationCloneAddresse string = "migration_clone_addresse"
|
migrationCloneAddress string = "migration_clone_addresse"
|
||||||
migrationCloneAddress string = "migration_clone_address"
|
|
||||||
migrationService string = "migration_service"
|
migrationService string = "migration_service"
|
||||||
migrationServiceAuthName string = "migration_service_auth_username"
|
migrationServiceAuthName string = "migration_service_auth_username"
|
||||||
migrationServiceAuthPassword string = "migration_service_auth_password"
|
migrationServiceAuthPassword string = "migration_service_auth_password"
|
||||||
@ -52,34 +47,6 @@ const (
|
|||||||
migrationLFSEndpoint string = "migration_lfs_endpoint"
|
migrationLFSEndpoint string = "migration_lfs_endpoint"
|
||||||
)
|
)
|
||||||
|
|
||||||
func searchUserByName(c *gitea.Client, name string) (res *gitea.User, err error) {
|
|
||||||
page := 1
|
|
||||||
|
|
||||||
for {
|
|
||||||
users, _, err := c.AdminListUsers(gitea.AdminListUsersOptions{
|
|
||||||
ListOptions: gitea.ListOptions{
|
|
||||||
Page: page,
|
|
||||||
PageSize: 50,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(users) == 0 {
|
|
||||||
return nil, fmt.Errorf("User with name %s could not be found", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, user := range users {
|
|
||||||
if user.UserName == name {
|
|
||||||
return user, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
page += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceRepoRead(d *schema.ResourceData, meta interface{}) (err error) {
|
func resourceRepoRead(d *schema.ResourceData, meta interface{}) (err error) {
|
||||||
client := meta.(*gitea.Client)
|
client := meta.(*gitea.Client)
|
||||||
|
|
||||||
@ -111,39 +78,21 @@ func resourceRepoCreate(d *schema.ResourceData, meta interface{}) (err error) {
|
|||||||
|
|
||||||
var repo *gitea.Repository
|
var repo *gitea.Repository
|
||||||
var resp *gitea.Response
|
var resp *gitea.Response
|
||||||
var orgRepo, hasAdmin bool
|
var orgRepo bool
|
||||||
|
|
||||||
_, resp, err = client.GetOrg(d.Get(repoOwner).(string))
|
_, resp, err = client.GetOrg(d.Get(repoOwner).(string))
|
||||||
|
|
||||||
if resp.StatusCode == 404 {
|
if resp.StatusCode == 404 {
|
||||||
_, err := searchUserByName(client, d.Get(repoOwner).(string))
|
|
||||||
if err != nil {
|
|
||||||
if strings.Contains(err.Error(), "could not be found") {
|
|
||||||
return errors.New(fmt.Sprintf("Creation of repository cound not proceed as owner %s is not present in gitea", d.Get(repoOwner).(string)))
|
|
||||||
}
|
|
||||||
tflog.Warn(context.Background(), "Error query for users. Assuming missing permissions and proceding with user permissions")
|
|
||||||
hasAdmin = false
|
|
||||||
} else {
|
|
||||||
hasAdmin = true
|
|
||||||
}
|
|
||||||
orgRepo = false
|
orgRepo = false
|
||||||
} else {
|
} else {
|
||||||
orgRepo = true
|
orgRepo = true
|
||||||
}
|
}
|
||||||
|
|
||||||
var cloneAddr string
|
if (d.Get(repoMirror)).(bool) {
|
||||||
if d.Get(migrationCloneAddresse).(string) != "" {
|
|
||||||
cloneAddr = d.Get(migrationCloneAddresse).(string)
|
|
||||||
} else {
|
|
||||||
cloneAddr = d.Get(migrationCloneAddress).(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cloneAddr != "" {
|
|
||||||
|
|
||||||
opts := gitea.MigrateRepoOption{
|
opts := gitea.MigrateRepoOption{
|
||||||
RepoName: d.Get(repoName).(string),
|
RepoName: d.Get(repoName).(string),
|
||||||
RepoOwner: d.Get(repoOwner).(string),
|
RepoOwner: d.Get(repoOwner).(string),
|
||||||
CloneAddr: cloneAddr,
|
CloneAddr: d.Get(migrationCloneAddress).(string),
|
||||||
Service: gitea.GitServiceType(d.Get(migrationService).(string)),
|
Service: gitea.GitServiceType(d.Get(migrationService).(string)),
|
||||||
Mirror: d.Get(repoMirror).(bool),
|
Mirror: d.Get(repoMirror).(bool),
|
||||||
Private: d.Get(repoPrivateFlag).(bool),
|
Private: d.Get(repoPrivateFlag).(bool),
|
||||||
@ -189,16 +138,12 @@ func resourceRepoCreate(d *schema.ResourceData, meta interface{}) (err error) {
|
|||||||
if orgRepo {
|
if orgRepo {
|
||||||
repo, _, err = client.CreateOrgRepo(d.Get(repoOwner).(string), opts)
|
repo, _, err = client.CreateOrgRepo(d.Get(repoOwner).(string), opts)
|
||||||
} else {
|
} else {
|
||||||
if hasAdmin {
|
repo, _, err = client.CreateRepo(opts)
|
||||||
repo, _, err = client.AdminCreateRepo(d.Get(repoOwner).(string), opts)
|
|
||||||
} else {
|
|
||||||
repo, _, err = client.CreateRepo(opts)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = setRepoResourceData(repo, d)
|
err = setRepoResourceData(repo, d)
|
||||||
@ -278,7 +223,6 @@ func respurceRepoDelete(d *schema.ResourceData, meta interface{}) (err error) {
|
|||||||
|
|
||||||
func setRepoResourceData(repo *gitea.Repository, d *schema.ResourceData) (err error) {
|
func setRepoResourceData(repo *gitea.Repository, d *schema.ResourceData) (err error) {
|
||||||
d.SetId(fmt.Sprintf("%d", repo.ID))
|
d.SetId(fmt.Sprintf("%d", repo.ID))
|
||||||
d.Set("username", repo.Owner.UserName)
|
|
||||||
d.Set("name", repo.Name)
|
d.Set("name", repo.Name)
|
||||||
d.Set("description", repo.Description)
|
d.Set("description", repo.Description)
|
||||||
d.Set("full_name", repo.FullName)
|
d.Set("full_name", repo.FullName)
|
||||||
@ -295,8 +239,8 @@ func setRepoResourceData(repo *gitea.Repository, d *schema.ResourceData) (err er
|
|||||||
d.Set("watchers", repo.Watchers)
|
d.Set("watchers", repo.Watchers)
|
||||||
d.Set("open_issue_count", repo.OpenIssues)
|
d.Set("open_issue_count", repo.OpenIssues)
|
||||||
d.Set("default_branch", repo.DefaultBranch)
|
d.Set("default_branch", repo.DefaultBranch)
|
||||||
d.Set("created", repo.Created.String())
|
d.Set("created", repo.Created)
|
||||||
d.Set("updated", repo.Updated.String())
|
d.Set("updated", repo.Updated)
|
||||||
d.Set("permission_admin", repo.Permissions.Admin)
|
d.Set("permission_admin", repo.Permissions.Admin)
|
||||||
d.Set("permission_push", repo.Permissions.Push)
|
d.Set("permission_push", repo.Permissions.Push)
|
||||||
d.Set("permission_pull", repo.Permissions.Pull)
|
d.Set("permission_pull", repo.Permissions.Pull)
|
||||||
@ -311,7 +255,7 @@ func resourceGiteaRepository() *schema.Resource {
|
|||||||
Update: resourceRepoUpdate,
|
Update: resourceRepoUpdate,
|
||||||
Delete: respurceRepoDelete,
|
Delete: respurceRepoDelete,
|
||||||
Importer: &schema.ResourceImporter{
|
Importer: &schema.ResourceImporter{
|
||||||
StateContext: schema.ImportStatePassthroughContext,
|
State: schema.ImportStatePassthrough,
|
||||||
},
|
},
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: map[string]*schema.Schema{
|
||||||
"username": {
|
"username": {
|
||||||
@ -501,13 +445,6 @@ func resourceGiteaRepository() *schema.Resource {
|
|||||||
Default: false,
|
Default: false,
|
||||||
},
|
},
|
||||||
"migration_clone_addresse": {
|
"migration_clone_addresse": {
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: false,
|
|
||||||
Optional: true,
|
|
||||||
ForceNew: true,
|
|
||||||
Description: "DEPRECATED in favor of `migration_clone_address`",
|
|
||||||
},
|
|
||||||
"migration_clone_address": {
|
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: false,
|
Required: false,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
@ -576,25 +513,11 @@ func resourceGiteaRepository() *schema.Resource {
|
|||||||
Optional: true,
|
Optional: true,
|
||||||
Default: "",
|
Default: "",
|
||||||
},
|
},
|
||||||
"clone_url": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
"html_url": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
"ssh_url": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Description: "`gitea_repository` manages a gitea repository.\n\n" +
|
Description: "`gitea_repository` manages a gitea repository.\n\n" +
|
||||||
"Per default this repository will be initializiled with the provided configuration (gitignore, License etc.).\n" +
|
"Per default this repository will be initializiled with the provided configuration (gitignore, License etc.).\n" +
|
||||||
"If the `username` property is set to a organisation name, the provider will try to look if this organisation exists " +
|
"If the `username` property is set to a organisation name, the provider will try to look if this organisation exists " +
|
||||||
"and create the repository under the organisation scope.\n\n" +
|
"and create the repository under the organisation scope.\n\n" +
|
||||||
"Repository migrations have some properties that are not available to regular repositories. These are all prefixed with `migration_`.\n" +
|
"Repository migrations have some properties that are not available to regular repositories. These are all prefixed with `migration_`.",
|
||||||
"Codeberg.org does currently not allow mirrors to be created. See FAQ Section of CodeBerg for more information: " +
|
|
||||||
"https://docs.codeberg.org/getting-started/faq/#why-am-i-not-allowed-to-set-up-an-automatic-mirror",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,169 +0,0 @@
|
|||||||
package gitea
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
deployKeyRepoId string = "repository"
|
|
||||||
deployKeyName string = "title"
|
|
||||||
deployKeyKey string = "key"
|
|
||||||
deployKeyReadOnly string = "read_only"
|
|
||||||
)
|
|
||||||
|
|
||||||
func resourceRepoKeyIdParts(d *schema.ResourceData) (bool, int64, int64, error) {
|
|
||||||
parts := strings.Split(d.Id(), "/")
|
|
||||||
if len(parts) != 2 {
|
|
||||||
return false, 0, 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
repoId, err := strconv.ParseInt(parts[0], 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return false, 0, 0, err
|
|
||||||
}
|
|
||||||
keyId, err := strconv.ParseInt(parts[1], 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return false, 0, 0, err
|
|
||||||
}
|
|
||||||
return true, repoId, keyId, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceRepoKeyRead(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
hasId, repoId, keyId, err := resourceRepoKeyIdParts(d)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !hasId {
|
|
||||||
d.SetId("")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
repo, resp, err := client.GetRepoByID(repoId)
|
|
||||||
if err != nil {
|
|
||||||
if resp.StatusCode == 404 {
|
|
||||||
d.SetId("")
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
key, resp, err := client.GetDeployKey(repo.Owner.UserName, repo.Name, keyId)
|
|
||||||
if err != nil {
|
|
||||||
if resp.StatusCode == 404 {
|
|
||||||
d.SetId("")
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = setRepoKeyResourceData(key, repoId, d)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceRepoKeyCreate(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
repo, _, err := client.GetRepoByID(int64(d.Get(deployKeyRepoId).(int)))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
dk, _, err := client.CreateDeployKey(repo.Owner.UserName, repo.Name, gitea.CreateKeyOption{
|
|
||||||
Title: d.Get(deployKeyName).(string),
|
|
||||||
ReadOnly: d.Get(deployKeyReadOnly).(bool),
|
|
||||||
Key: d.Get(deployKeyKey).(string),
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
setRepoKeyResourceData(dk, repo.ID, d)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func respurceRepoKeyDelete(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
hasId, repoId, keyId, err := resourceRepoKeyIdParts(d)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !hasId {
|
|
||||||
d.SetId("")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
repo, resp, err := client.GetRepoByID(repoId)
|
|
||||||
if err != nil {
|
|
||||||
if resp.StatusCode == 404 {
|
|
||||||
d.SetId("")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
client.DeleteDeployKey(repo.Owner.UserName, repo.Name, keyId)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setRepoKeyResourceData(dk *gitea.DeployKey, repoId int64, d *schema.ResourceData) (err error) {
|
|
||||||
d.SetId(fmt.Sprintf("%d/%d", repoId, dk.ID))
|
|
||||||
d.Set(deployKeyRepoId, repoId)
|
|
||||||
d.Set(deployKeyReadOnly, dk.ReadOnly)
|
|
||||||
d.Set(deployKeyKey, dk.Key)
|
|
||||||
d.Set(deployKeyName, dk.Title)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceGiteaRepositoryKey() *schema.Resource {
|
|
||||||
return &schema.Resource{
|
|
||||||
Read: resourceRepoKeyRead,
|
|
||||||
Create: resourceRepoKeyCreate,
|
|
||||||
Delete: respurceRepoKeyDelete,
|
|
||||||
Importer: &schema.ResourceImporter{
|
|
||||||
StateContext: schema.ImportStatePassthroughContext,
|
|
||||||
},
|
|
||||||
Schema: map[string]*schema.Schema{
|
|
||||||
deployKeyRepoId: {
|
|
||||||
Type: schema.TypeInt,
|
|
||||||
Required: true,
|
|
||||||
ForceNew: true,
|
|
||||||
Description: "The ID of the repository where the deploy key belongs to",
|
|
||||||
},
|
|
||||||
deployKeyKey: {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
ForceNew: true,
|
|
||||||
Description: "Armored SSH key to add",
|
|
||||||
},
|
|
||||||
deployKeyReadOnly: {
|
|
||||||
Type: schema.TypeBool,
|
|
||||||
Required: false,
|
|
||||||
Optional: true,
|
|
||||||
Default: true,
|
|
||||||
ForceNew: true,
|
|
||||||
Description: "Whether this key has read or read/write access",
|
|
||||||
},
|
|
||||||
deployKeyName: {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
ForceNew: true,
|
|
||||||
Description: "Name of the deploy key",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Description: "`gitea_repository_key` manages a deploy key for a single gitea_repository.\n\n" +
|
|
||||||
"Every key needs a unique name and unique key, i.e. no key can be added twice to the same repo",
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,388 +0,0 @@
|
|||||||
package gitea
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
TeamName string = "name"
|
|
||||||
TeamOrg string = "organisation"
|
|
||||||
TeamDescription string = "description"
|
|
||||||
TeamPermissions string = "permission"
|
|
||||||
TeamCreateRepoFlag string = "can_create_repos"
|
|
||||||
TeamIncludeAllReposFlag string = "include_all_repositories"
|
|
||||||
TeamUnits string = "units"
|
|
||||||
TeamMembers string = "members"
|
|
||||||
TeamRepositories string = "repositories"
|
|
||||||
)
|
|
||||||
|
|
||||||
func resourceTeamRead(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
id, err := strconv.ParseInt(d.Id(), 10, 64)
|
|
||||||
|
|
||||||
var resp *gitea.Response
|
|
||||||
var team *gitea.Team
|
|
||||||
|
|
||||||
team, resp, err = client.GetTeam(id)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if resp.StatusCode == 404 {
|
|
||||||
d.SetId("")
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = setTeamResourceData(team, d, meta)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceTeamCreate(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
var team *gitea.Team
|
|
||||||
var units []gitea.RepoUnitType
|
|
||||||
|
|
||||||
if strings.Contains(d.Get(TeamUnits).(string), "repo.code") {
|
|
||||||
units = append(units, gitea.RepoUnitCode)
|
|
||||||
}
|
|
||||||
if strings.Contains(d.Get(TeamUnits).(string), "repo.issues") {
|
|
||||||
units = append(units, gitea.RepoUnitIssues)
|
|
||||||
}
|
|
||||||
if strings.Contains(d.Get(TeamUnits).(string), "repo.ext_issues") {
|
|
||||||
units = append(units, gitea.RepoUnitExtIssues)
|
|
||||||
}
|
|
||||||
if strings.Contains(d.Get(TeamUnits).(string), "repo.wiki") {
|
|
||||||
units = append(units, gitea.RepoUnitWiki)
|
|
||||||
}
|
|
||||||
if strings.Contains(d.Get(TeamUnits).(string), "repo.pulls") {
|
|
||||||
units = append(units, gitea.RepoUnitPulls)
|
|
||||||
}
|
|
||||||
if strings.Contains(d.Get(TeamUnits).(string), "repo.releases") {
|
|
||||||
units = append(units, gitea.RepoUnitReleases)
|
|
||||||
}
|
|
||||||
if strings.Contains(d.Get(TeamUnits).(string), "repo.ext_wiki") {
|
|
||||||
units = append(units, gitea.RepoUnitExtWiki)
|
|
||||||
}
|
|
||||||
if strings.Contains(d.Get(TeamUnits).(string), "repo.projects") {
|
|
||||||
units = append(units, gitea.RepoUnitProjects)
|
|
||||||
}
|
|
||||||
|
|
||||||
includeAllRepos := d.Get(TeamIncludeAllReposFlag).(bool)
|
|
||||||
|
|
||||||
opts := gitea.CreateTeamOption{
|
|
||||||
Name: d.Get(TeamName).(string),
|
|
||||||
Description: d.Get(TeamDescription).(string),
|
|
||||||
Permission: gitea.AccessMode(d.Get(TeamPermissions).(string)),
|
|
||||||
CanCreateOrgRepo: d.Get(TeamCreateRepoFlag).(bool),
|
|
||||||
IncludesAllRepositories: includeAllRepos,
|
|
||||||
Units: units,
|
|
||||||
}
|
|
||||||
|
|
||||||
team, _, err = client.CreateTeam(d.Get(TeamOrg).(string), opts)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
users := d.Get(TeamMembers).([]interface{})
|
|
||||||
|
|
||||||
for _, user := range users {
|
|
||||||
if user != "" {
|
|
||||||
_, err = client.AddTeamMember(team.ID, user.(string))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !includeAllRepos {
|
|
||||||
err = setTeamRepositories(team, d, meta, false)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = setTeamResourceData(team, d, meta)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceTeamUpdate(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
id, err := strconv.ParseInt(d.Id(), 10, 64)
|
|
||||||
|
|
||||||
var resp *gitea.Response
|
|
||||||
var team *gitea.Team
|
|
||||||
|
|
||||||
team, resp, err = client.GetTeam(id)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if resp.StatusCode == 404 {
|
|
||||||
resourceTeamCreate(d, meta)
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
description := d.Get(TeamDescription).(string)
|
|
||||||
canCreateRepo := d.Get(TeamCreateRepoFlag).(bool)
|
|
||||||
includeAllRepos := d.Get(TeamIncludeAllReposFlag).(bool)
|
|
||||||
|
|
||||||
var units []gitea.RepoUnitType
|
|
||||||
|
|
||||||
if strings.Contains(d.Get(TeamUnits).(string), "repo.code") {
|
|
||||||
units = append(units, gitea.RepoUnitCode)
|
|
||||||
}
|
|
||||||
if strings.Contains(d.Get(TeamUnits).(string), "repo.issues") {
|
|
||||||
units = append(units, gitea.RepoUnitIssues)
|
|
||||||
}
|
|
||||||
if strings.Contains(d.Get(TeamUnits).(string), "repo.ext_issues") {
|
|
||||||
units = append(units, gitea.RepoUnitExtIssues)
|
|
||||||
}
|
|
||||||
if strings.Contains(d.Get(TeamUnits).(string), "repo.wiki") {
|
|
||||||
units = append(units, gitea.RepoUnitWiki)
|
|
||||||
}
|
|
||||||
if strings.Contains(d.Get(TeamUnits).(string), "repo.pulls") {
|
|
||||||
units = append(units, gitea.RepoUnitPulls)
|
|
||||||
}
|
|
||||||
if strings.Contains(d.Get(TeamUnits).(string), "repo.releases") {
|
|
||||||
units = append(units, gitea.RepoUnitReleases)
|
|
||||||
}
|
|
||||||
if strings.Contains(d.Get(TeamUnits).(string), "repo.ext_wiki") {
|
|
||||||
units = append(units, gitea.RepoUnitExtWiki)
|
|
||||||
}
|
|
||||||
if strings.Contains(d.Get(TeamUnits).(string), "repo.projects") {
|
|
||||||
units = append(units, gitea.RepoUnitProjects)
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := gitea.EditTeamOption{
|
|
||||||
Name: d.Get(TeamName).(string),
|
|
||||||
Description: &description,
|
|
||||||
Permission: gitea.AccessMode(d.Get(TeamPermissions).(string)),
|
|
||||||
CanCreateOrgRepo: &canCreateRepo,
|
|
||||||
IncludesAllRepositories: &includeAllRepos,
|
|
||||||
Units: units,
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err = client.EditTeam(id, opts)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
users := d.Get(TeamMembers).([]interface{})
|
|
||||||
|
|
||||||
for _, user := range users {
|
|
||||||
if user != "" {
|
|
||||||
_, err = client.AddTeamMember(team.ID, user.(string))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !includeAllRepos {
|
|
||||||
err = setTeamRepositories(team, d, meta, true)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
team, _, _ = client.GetTeam(id)
|
|
||||||
|
|
||||||
err = setTeamResourceData(team, d, meta)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceTeamDelete(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
id, err := strconv.ParseInt(d.Id(), 10, 64)
|
|
||||||
|
|
||||||
var resp *gitea.Response
|
|
||||||
|
|
||||||
resp, err = client.DeleteTeam(id)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if resp.StatusCode == 404 {
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func setTeamResourceData(team *gitea.Team, d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
if err := client.CheckServerVersionConstraint(">= 1.19.4"); err != nil {
|
|
||||||
d.Set(TeamOrg, d.Get(TeamOrg).(string))
|
|
||||||
} else {
|
|
||||||
d.Set(TeamOrg, team.Organization.UserName)
|
|
||||||
}
|
|
||||||
d.SetId(fmt.Sprintf("%d", team.ID))
|
|
||||||
d.Set(TeamCreateRepoFlag, team.CanCreateOrgRepo)
|
|
||||||
d.Set(TeamDescription, team.Description)
|
|
||||||
d.Set(TeamName, team.Name)
|
|
||||||
d.Set(TeamPermissions, string(team.Permission))
|
|
||||||
d.Set(TeamIncludeAllReposFlag, team.IncludesAllRepositories)
|
|
||||||
d.Set(TeamUnits, d.Get(TeamUnits).(string))
|
|
||||||
d.Set(TeamMembers, d.Get(TeamMembers))
|
|
||||||
d.Set(TeamRepositories, d.Get(TeamRepositories))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceGiteaTeam() *schema.Resource {
|
|
||||||
return &schema.Resource{
|
|
||||||
Read: resourceTeamRead,
|
|
||||||
Create: resourceTeamCreate,
|
|
||||||
Update: resourceTeamUpdate,
|
|
||||||
Delete: resourceTeamDelete,
|
|
||||||
Importer: &schema.ResourceImporter{
|
|
||||||
StateContext: schema.ImportStatePassthroughContext,
|
|
||||||
},
|
|
||||||
Schema: map[string]*schema.Schema{
|
|
||||||
"name": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
ForceNew: true,
|
|
||||||
Description: "Name of the Team",
|
|
||||||
},
|
|
||||||
"organisation": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
ForceNew: true,
|
|
||||||
Description: "The organisation which this Team is part of.",
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: false,
|
|
||||||
Optional: true,
|
|
||||||
Default: "",
|
|
||||||
Description: "Description of the Team",
|
|
||||||
},
|
|
||||||
"permission": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: false,
|
|
||||||
Optional: true,
|
|
||||||
Default: "",
|
|
||||||
Description: "Permissions associated with this Team\n" +
|
|
||||||
"Can be `none`, `read`, `write`, `admin` or `owner`",
|
|
||||||
},
|
|
||||||
"can_create_repos": {
|
|
||||||
Type: schema.TypeBool,
|
|
||||||
Required: false,
|
|
||||||
Optional: true,
|
|
||||||
Default: true,
|
|
||||||
Description: "Flag if the Teams members should be able to create Rpositories in the Organisation",
|
|
||||||
},
|
|
||||||
"include_all_repositories": {
|
|
||||||
Type: schema.TypeBool,
|
|
||||||
Required: false,
|
|
||||||
Optional: true,
|
|
||||||
Default: true,
|
|
||||||
Description: "Flag if the Teams members should have access to all Repositories in the Organisation",
|
|
||||||
},
|
|
||||||
"units": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: false,
|
|
||||||
Optional: true,
|
|
||||||
Default: "[repo.code, repo.issues, repo.ext_issues, repo.wiki, repo.pulls, repo.releases, repo.projects, repo.ext_wiki]",
|
|
||||||
Description: "List of types of Repositories that should be allowed to be created from Team members.\n" +
|
|
||||||
"Can be `repo.code`, `repo.issues`, `repo.ext_issues`, `repo.wiki`, `repo.pulls`, `repo.releases`, `repo.projects` and/or `repo.ext_wiki`",
|
|
||||||
},
|
|
||||||
"members": {
|
|
||||||
Type: schema.TypeList,
|
|
||||||
Elem: &schema.Schema{
|
|
||||||
Type: schema.TypeString,
|
|
||||||
},
|
|
||||||
Optional: true,
|
|
||||||
Required: false,
|
|
||||||
Computed: true,
|
|
||||||
Description: "List of Users that should be part of this team",
|
|
||||||
},
|
|
||||||
"repositories": {
|
|
||||||
Type: schema.TypeList,
|
|
||||||
Elem: &schema.Schema{
|
|
||||||
Type: schema.TypeString,
|
|
||||||
},
|
|
||||||
Optional: true,
|
|
||||||
Required: false,
|
|
||||||
Computed: true,
|
|
||||||
Description: "List of Repositories that should be part of this team",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Description: "`gitea_team` manages Team that are part of an organisation.",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setTeamRepositories(team *gitea.Team, d *schema.ResourceData, meta interface{}, update bool) (err error) {
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
org := d.Get(TeamOrg).(string)
|
|
||||||
|
|
||||||
repositories := make(map[string]bool)
|
|
||||||
for _, repo := range d.Get(TeamRepositories).([]interface{}) {
|
|
||||||
if repo != "" {
|
|
||||||
repositories[repo.(string)] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if update {
|
|
||||||
page := 1
|
|
||||||
|
|
||||||
for {
|
|
||||||
var existingRepositories []*gitea.Repository
|
|
||||||
existingRepositories, _, err = client.ListTeamRepositories(team.ID, gitea.ListTeamRepositoriesOptions{
|
|
||||||
ListOptions: gitea.ListOptions{
|
|
||||||
Page: page,
|
|
||||||
PageSize: 50,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("[ERROR] Error listeng team repositories: %s", err))
|
|
||||||
}
|
|
||||||
if len(existingRepositories) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, exr := range existingRepositories {
|
|
||||||
_, exists := repositories[exr.Name]
|
|
||||||
if exists {
|
|
||||||
repositories[exr.Name] = false
|
|
||||||
} else {
|
|
||||||
_, err = client.RemoveTeamRepository(team.ID, org, exr.Name)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("[ERROR] Error removing team repository %q: %s", exr.Name, err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
page += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for repo, flag := range repositories {
|
|
||||||
if flag {
|
|
||||||
_, err = client.AddTeamRepository(team.ID, org, repo)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("[ERROR] Error adding team repository %q: %s", repo, err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
@ -1,151 +0,0 @@
|
|||||||
package gitea
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
TokenUsername string = "username"
|
|
||||||
TokenName string = "name"
|
|
||||||
TokenHash string = "token"
|
|
||||||
TokenLastEight string = "last_eight"
|
|
||||||
)
|
|
||||||
|
|
||||||
func searchTokenById(c *gitea.Client, id int64) (res *gitea.AccessToken, err error) {
|
|
||||||
page := 1
|
|
||||||
|
|
||||||
for {
|
|
||||||
tokens, _, err := c.ListAccessTokens(gitea.ListAccessTokensOptions{
|
|
||||||
ListOptions: gitea.ListOptions{
|
|
||||||
Page: page,
|
|
||||||
PageSize: 50,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(tokens) == 0 {
|
|
||||||
return nil, fmt.Errorf("Token with ID %d could not be found", id)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, token := range tokens {
|
|
||||||
if token.ID == id {
|
|
||||||
return token, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
page += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceTokenCreate(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
var opt gitea.CreateAccessTokenOption
|
|
||||||
opt.Name = d.Get(TokenName).(string)
|
|
||||||
|
|
||||||
token, _, err := client.CreateAccessToken(opt)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = setTokenResourceData(token, d)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceTokenRead(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
|
|
||||||
var token *gitea.AccessToken
|
|
||||||
|
|
||||||
id, err := strconv.ParseInt(d.Id(), 10, 64)
|
|
||||||
|
|
||||||
token, err = searchTokenById(client, id)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = setTokenResourceData(token, d)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceTokenDelete(d *schema.ResourceData, meta interface{}) (err error) {
|
|
||||||
|
|
||||||
client := meta.(*gitea.Client)
|
|
||||||
var resp *gitea.Response
|
|
||||||
|
|
||||||
resp, err = client.DeleteAccessToken(d.Get(TokenName).(string))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if resp.StatusCode == 404 {
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func setTokenResourceData(token *gitea.AccessToken, d *schema.ResourceData) (err error) {
|
|
||||||
|
|
||||||
d.SetId(fmt.Sprintf("%d", token.ID))
|
|
||||||
d.Set(TokenName, token.Name)
|
|
||||||
if token.Token != "" {
|
|
||||||
d.Set(TokenHash, token.Token)
|
|
||||||
}
|
|
||||||
d.Set(TokenLastEight, token.TokenLastEight)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceGiteaToken() *schema.Resource {
|
|
||||||
return &schema.Resource{
|
|
||||||
Read: resourceTokenRead,
|
|
||||||
Create: resourceTokenCreate,
|
|
||||||
Delete: resourceTokenDelete,
|
|
||||||
Importer: &schema.ResourceImporter{
|
|
||||||
StateContext: schema.ImportStatePassthroughContext,
|
|
||||||
},
|
|
||||||
Schema: map[string]*schema.Schema{
|
|
||||||
"username": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
ForceNew: true,
|
|
||||||
Description: "The owner of the Access Token",
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
ForceNew: true,
|
|
||||||
Description: "The name of the Access Token",
|
|
||||||
},
|
|
||||||
"token": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
Sensitive: true,
|
|
||||||
Description: "The actual Access Token",
|
|
||||||
},
|
|
||||||
"last_eight": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Description: "`gitea_token` manages gitea Access Tokens.\n\n" +
|
|
||||||
"Due to upstream limitations (see https://gitea.com/gitea/go-sdk/issues/610) this resource\n" +
|
|
||||||
"can only be used with username/password provider configuration.\n\n" +
|
|
||||||
"WARNING:\n" +
|
|
||||||
"Tokens will be stored in the terraform state!",
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,7 +5,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
"code.gitea.io/sdk/gitea"
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -196,6 +196,7 @@ func resourceUserDelete(d *schema.ResourceData, meta interface{}) (err error) {
|
|||||||
|
|
||||||
func setUserResourceData(user *gitea.User, d *schema.ResourceData) (err error) {
|
func setUserResourceData(user *gitea.User, d *schema.ResourceData) (err error) {
|
||||||
d.SetId(fmt.Sprintf("%d", user.ID))
|
d.SetId(fmt.Sprintf("%d", user.ID))
|
||||||
|
d.Set("id", user.ID)
|
||||||
d.Set(userName, user.UserName)
|
d.Set(userName, user.UserName)
|
||||||
d.Set(userEmail, user.Email)
|
d.Set(userEmail, user.Email)
|
||||||
d.Set(userFullName, user.FullName)
|
d.Set(userFullName, user.FullName)
|
||||||
|
106
go.mod
106
go.mod
@ -4,70 +4,80 @@ go 1.18
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
code.gitea.io/sdk/gitea v0.15.1
|
code.gitea.io/sdk/gitea v0.15.1
|
||||||
github.com/hashicorp/terraform-plugin-docs v0.16.0
|
github.com/hashicorp/terraform-plugin-docs v0.7.0
|
||||||
github.com/hashicorp/terraform-plugin-log v0.9.0
|
github.com/hashicorp/terraform-plugin-sdk v1.13.0
|
||||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.27.0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
cloud.google.com/go v0.45.1 // indirect
|
||||||
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.0 // indirect
|
||||||
github.com/Masterminds/sprig/v3 v3.2.2 // indirect
|
github.com/Masterminds/semver v1.5.0 // indirect
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
|
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
||||||
github.com/agext/levenshtein v1.2.2 // indirect
|
github.com/agext/levenshtein v1.2.2 // indirect
|
||||||
|
github.com/apparentlymart/go-cidr v1.0.1 // indirect
|
||||||
|
github.com/apparentlymart/go-textseg v1.0.0 // indirect
|
||||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||||
github.com/armon/go-radix v1.0.0 // indirect
|
github.com/armon/go-radix v1.0.0 // indirect
|
||||||
|
github.com/aws/aws-sdk-go v1.25.3 // indirect
|
||||||
|
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||||
github.com/bgentry/speakeasy v0.1.0 // indirect
|
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||||
github.com/cloudflare/circl v1.3.3 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/fatih/color v1.13.0 // indirect
|
github.com/fatih/color v1.7.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.3.4 // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.7 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.1.2 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
|
||||||
|
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||||
github.com/hashicorp/go-checkpoint v0.5.0 // indirect
|
github.com/hashicorp/go-checkpoint v0.5.0 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect
|
github.com/hashicorp/go-getter v1.4.0 // indirect
|
||||||
github.com/hashicorp/go-hclog v1.5.0 // indirect
|
github.com/hashicorp/go-hclog v0.9.2 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/hashicorp/go-plugin v1.4.10 // indirect
|
github.com/hashicorp/go-plugin v1.0.1 // indirect
|
||||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
github.com/hashicorp/go-safetemp v1.0.0 // indirect
|
||||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
github.com/hashicorp/go-uuid v1.0.1 // indirect
|
||||||
github.com/hashicorp/hc-install v0.5.2 // indirect
|
github.com/hashicorp/go-version v1.4.0 // indirect
|
||||||
github.com/hashicorp/hcl/v2 v2.17.0 // indirect
|
github.com/hashicorp/golang-lru v0.5.1 // indirect
|
||||||
|
github.com/hashicorp/hc-install v0.3.1 // indirect
|
||||||
|
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f // indirect
|
||||||
|
github.com/hashicorp/hcl/v2 v2.0.0 // indirect
|
||||||
github.com/hashicorp/logutils v1.0.0 // indirect
|
github.com/hashicorp/logutils v1.0.0 // indirect
|
||||||
github.com/hashicorp/terraform-exec v0.18.1 // indirect
|
github.com/hashicorp/terraform-config-inspect v0.0.0-20191115094559-17f92b0546e8 // indirect
|
||||||
github.com/hashicorp/terraform-json v0.17.1 // indirect
|
github.com/hashicorp/terraform-exec v0.16.0 // indirect
|
||||||
github.com/hashicorp/terraform-plugin-go v0.16.0 // indirect
|
github.com/hashicorp/terraform-json v0.13.0 // indirect
|
||||||
github.com/hashicorp/terraform-registry-address v0.2.1 // indirect
|
github.com/hashicorp/terraform-plugin-test v1.3.0 // indirect
|
||||||
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
|
github.com/hashicorp/terraform-svchost v0.0.0-20191011084731-65d371908596 // indirect
|
||||||
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect
|
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect
|
||||||
github.com/huandu/xstrings v1.3.2 // indirect
|
github.com/huandu/xstrings v1.3.2 // indirect
|
||||||
github.com/imdario/mergo v0.3.13 // indirect
|
github.com/imdario/mergo v0.3.12 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
|
||||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||||
github.com/mitchellh/cli v1.1.5 // indirect
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
|
github.com/mitchellh/cli v1.1.2 // indirect
|
||||||
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
|
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
|
||||||
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
|
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.1.2 // indirect
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||||
github.com/oklog/run v1.0.0 // indirect
|
github.com/oklog/run v1.0.0 // indirect
|
||||||
github.com/posener/complete v1.2.3 // indirect
|
github.com/posener/complete v1.2.1 // indirect
|
||||||
github.com/russross/blackfriday v1.6.0 // indirect
|
github.com/russross/blackfriday v1.6.0 // indirect
|
||||||
github.com/shopspring/decimal v1.3.1 // indirect
|
github.com/spf13/afero v1.2.2 // indirect
|
||||||
github.com/spf13/cast v1.5.0 // indirect
|
github.com/ulikunitz/xz v0.5.5 // indirect
|
||||||
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect
|
||||||
github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
|
github.com/vmihailenco/tagparser v0.1.1 // indirect
|
||||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
github.com/zclconf/go-cty v1.10.0 // indirect
|
||||||
github.com/zclconf/go-cty v1.13.2 // indirect
|
github.com/zclconf/go-cty-yaml v1.0.1 // indirect
|
||||||
golang.org/x/crypto v0.10.0 // indirect
|
go.opencensus.io v0.22.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
|
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect
|
||||||
golang.org/x/mod v0.11.0 // indirect
|
golang.org/x/net v0.0.0-20210326060303-6b1517762897 // indirect
|
||||||
golang.org/x/net v0.11.0 // indirect
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect
|
||||||
golang.org/x/sys v0.9.0 // indirect
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
|
||||||
golang.org/x/text v0.11.0 // indirect
|
golang.org/x/text v0.3.5 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/api v0.9.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
google.golang.org/appengine v1.6.5 // indirect
|
||||||
google.golang.org/grpc v1.56.0 // indirect
|
google.golang.org/genproto v0.0.0-20200310143817-43be25429f5a // indirect
|
||||||
google.golang.org/protobuf v1.30.0 // indirect
|
google.golang.org/grpc v1.27.1 // indirect
|
||||||
)
|
)
|
||||||
|
457
go.sum
457
go.sum
@ -1,244 +1,429 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
|
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||||
|
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||||
|
cloud.google.com/go v0.45.1 h1:lRi0CHyU+ytlvylOlFKKq0af6JncuyoRh1J+QJBqQx0=
|
||||||
|
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||||
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
|
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||||
code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
|
code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
|
||||||
code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M=
|
code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M=
|
||||||
code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA=
|
code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA=
|
||||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
|
||||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||||
github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
|
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||||
github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8=
|
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
|
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
|
||||||
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
|
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA=
|
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
|
github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
|
||||||
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
|
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||||
|
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ=
|
||||||
|
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||||
|
github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
|
||||||
|
github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
|
||||||
|
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||||
github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE=
|
github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE=
|
||||||
github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||||
github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
|
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=
|
||||||
|
github.com/andybalholm/crlf v0.0.0-20171020200849-670099aa064f/go.mod h1:k8feO4+kXDxro6ErPXBRTJ/ro2mf0SsFG8s7doP9kJE=
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||||
|
github.com/apparentlymart/go-cidr v1.0.1 h1:NmIwLZ/KdsjIUlhf+/Np40atNXm/+lZ5txfTJ/SpF+U=
|
||||||
|
github.com/apparentlymart/go-cidr v1.0.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc=
|
||||||
|
github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
|
||||||
|
github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I=
|
||||||
|
github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
|
||||||
|
github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0=
|
||||||
|
github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
|
||||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
|
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
|
||||||
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
|
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
|
||||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
|
github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
|
||||||
|
github.com/aws/aws-sdk-go v1.25.3 h1:uM16hIw9BotjZKMZlX05SN2EFtaWfi/NonPKIARiBLQ=
|
||||||
|
github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
|
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
|
||||||
|
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
|
||||||
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
|
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
|
github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
|
||||||
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||||
|
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
|
||||||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
||||||
github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
|
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
|
||||||
github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHsk=
|
github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||||
|
github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34=
|
||||||
|
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||||
|
github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
|
||||||
|
github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4=
|
||||||
|
github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
|
||||||
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||||
|
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
|
||||||
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk=
|
||||||
|
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||||
|
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
||||||
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
|
||||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
|
||||||
github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU=
|
github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU=
|
||||||
github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg=
|
github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||||
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI=
|
github.com/hashicorp/go-getter v1.4.0 h1:ENHNi8494porjD0ZhIrjlAHnveSFhY7hvOJrV/fsKkw=
|
||||||
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs=
|
github.com/hashicorp/go-getter v1.4.0/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY=
|
||||||
github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
|
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
|
||||||
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||||
github.com/hashicorp/go-plugin v1.4.10 h1:xUbmA4jC6Dq163/fWcp8P3JuHilrHHMLNRxzGQJ9hNk=
|
github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE=
|
||||||
github.com/hashicorp/go-plugin v1.4.10/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0=
|
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
|
||||||
|
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
|
||||||
|
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
|
||||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
|
||||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
|
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
github.com/hashicorp/go-version v1.4.0 h1:aAQzgqIrRKRa7w75CKpbBxYsmUoPjzVm1W59ca1L0J4=
|
||||||
github.com/hashicorp/hc-install v0.5.2 h1:SfwMFnEXVVirpwkDuSF5kymUOhrUxrTq3udEseZdOD0=
|
github.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/hashicorp/hc-install v0.5.2/go.mod h1:9QISwe6newMWIfEiXpzuu1k9HAGtQYgnSH8H9T8wmoI=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/hcl/v2 v2.17.0 h1:z1XvSUyXd1HP10U4lrLg5e0JMVz6CPaJvAgxM0KNZVY=
|
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||||
github.com/hashicorp/hcl/v2 v2.17.0/go.mod h1:gJyW2PTShkJqQBKpAmPO3yxMxIuoXkOF2TpqXzrQyx4=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/hc-install v0.3.1 h1:VIjllE6KyAI1A244G8kTaHXy+TL5/XYzvrtFi8po/Yk=
|
||||||
|
github.com/hashicorp/hc-install v0.3.1/go.mod h1:3LCdWcCDS1gaHC9mhHCGbkYfoY6vdsKohGjugbZdZak=
|
||||||
|
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f h1:UdxlrJz4JOnY8W+DbLISwf2B8WXEolNRA8BGCwI9jws=
|
||||||
|
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
|
||||||
|
github.com/hashicorp/hcl/v2 v2.0.0 h1:efQznTz+ydmQXq3BOnRa3AXzvCeTq1P4dKj/z5GLlY8=
|
||||||
|
github.com/hashicorp/hcl/v2 v2.0.0/go.mod h1:oVVDG71tEinNGYCxinCYadcmKU9bglqW9pV3txagJ90=
|
||||||
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
|
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
|
||||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||||
github.com/hashicorp/terraform-exec v0.18.1 h1:LAbfDvNQU1l0NOQlTuudjczVhHj061fNX5H8XZxHlH4=
|
github.com/hashicorp/terraform-config-inspect v0.0.0-20191115094559-17f92b0546e8 h1:+RyjwU+Gnd/aTJBPZVDNm903eXVjjqhbaR4Ypx3xYyY=
|
||||||
github.com/hashicorp/terraform-exec v0.18.1/go.mod h1:58wg4IeuAJ6LVsLUeD2DWZZoc/bYi6dzhLHzxM41980=
|
github.com/hashicorp/terraform-config-inspect v0.0.0-20191115094559-17f92b0546e8/go.mod h1:p+ivJws3dpqbp1iP84+npOyAmTTOLMgCzrXd3GSdn/A=
|
||||||
github.com/hashicorp/terraform-json v0.17.1 h1:eMfvh/uWggKmY7Pmb3T85u86E2EQg6EQHgyRwf3RkyA=
|
github.com/hashicorp/terraform-exec v0.16.0 h1:XUh9pJPcbfZsuhReVvmRarQTaiiCnYogFCCjOvEYuug=
|
||||||
github.com/hashicorp/terraform-json v0.17.1/go.mod h1:Huy6zt6euxaY9knPAFKjUITn8QxUFIe9VuSzb4zn/0o=
|
github.com/hashicorp/terraform-exec v0.16.0/go.mod h1:wB5JHmjxZ/YVNZuv9npAXKmz5pGyxy8PSi0GRR0+YjA=
|
||||||
github.com/hashicorp/terraform-plugin-docs v0.16.0 h1:UmxFr3AScl6Wged84jndJIfFccGyBZn52KtMNsS12dI=
|
github.com/hashicorp/terraform-json v0.4.0/go.mod h1:eAbqb4w0pSlRmdvl8fOyHAi/+8jnkVYN28gJkSJrLhU=
|
||||||
github.com/hashicorp/terraform-plugin-docs v0.16.0/go.mod h1:M3ZrlKBJAbPMtNOPwHicGi1c+hZUh7/g0ifT/z7TVfA=
|
github.com/hashicorp/terraform-json v0.13.0 h1:Li9L+lKD1FO5RVFRM1mMMIBDoUHslOniyEi5CM+FWGY=
|
||||||
github.com/hashicorp/terraform-plugin-go v0.16.0 h1:DSOQ0rz5FUiVO4NUzMs8ln9gsPgHMTsfns7Nk+6gPuE=
|
github.com/hashicorp/terraform-json v0.13.0/go.mod h1:y5OdLBCT+rxbwnpxZs9kGL7R9ExU76+cpdY8zHwoazk=
|
||||||
github.com/hashicorp/terraform-plugin-go v0.16.0/go.mod h1:4sn8bFuDbt+2+Yztt35IbOrvZc0zyEi87gJzsTgCES8=
|
github.com/hashicorp/terraform-plugin-docs v0.7.0 h1:7XKAOYHAxghe7q4/vx468X43X9GikdQ2dxtmcu2gQv0=
|
||||||
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
|
github.com/hashicorp/terraform-plugin-docs v0.7.0/go.mod h1:57CICKfW7/KbW4lPhKOledyT6vu1LeAOzuvWXsVaxUE=
|
||||||
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
|
github.com/hashicorp/terraform-plugin-sdk v1.13.0 h1:8v2/ZNiI12OHxEn8pzJ3noCHyRc0biKbKj+iFv5ZWKw=
|
||||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.27.0 h1:I8efBnjuDrgPjNF1MEypHy48VgcTIUY4X6rOFunrR3Y=
|
github.com/hashicorp/terraform-plugin-sdk v1.13.0/go.mod h1:HiWIPD/T9HixIhQUwaSoDQxo4BLFdmiBi/Qz5gjB8Q0=
|
||||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.27.0/go.mod h1:cUEP4ly/nxlHy5HzD6YRrHydtlheGvGRJDhiWqqVik4=
|
github.com/hashicorp/terraform-plugin-test v1.3.0 h1:hU5LoxrOn9qvOo+LTKN6mSav2J+dAMprbdxJPEQvp4U=
|
||||||
github.com/hashicorp/terraform-registry-address v0.2.1 h1:QuTf6oJ1+WSflJw6WYOHhLgwUiQ0FrROpHPYFtwTYWM=
|
github.com/hashicorp/terraform-plugin-test v1.3.0/go.mod h1:QIJHYz8j+xJtdtLrFTlzQVC0ocr3rf/OjIpgZLK56Hs=
|
||||||
github.com/hashicorp/terraform-registry-address v0.2.1/go.mod h1:BSE9fIFzp0qWsJUUyGquo4ldV9k2n+psif6NYkBRS3Y=
|
github.com/hashicorp/terraform-svchost v0.0.0-20191011084731-65d371908596 h1:hjyO2JsNZUKT1ym+FAdlBEkGPevazYsmVgIMw7dVELg=
|
||||||
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
|
github.com/hashicorp/terraform-svchost v0.0.0-20191011084731-65d371908596/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg=
|
||||||
github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
|
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||||
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ=
|
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ=
|
||||||
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||||
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
|
||||||
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
||||||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
|
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||||
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
|
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||||
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||||
|
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||||
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
|
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck=
|
||||||
|
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
|
github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||||
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
|
||||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||||
|
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
|
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||||
github.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng=
|
github.com/mitchellh/cli v1.1.2 h1:PvH+lL2B7IQ101xQL63Of8yFS2y+aDlsFcsqNc+u/Kw=
|
||||||
github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4=
|
github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4=
|
||||||
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||||
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||||
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
|
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||||
|
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
|
||||||
|
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||||
|
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||||
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
|
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
|
||||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
|
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
|
||||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo=
|
github.com/posener/complete v1.2.1 h1:LrvDIY//XNo65Lq84G/akBuMGlawHvGBABv8f/ZN6DI=
|
||||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
github.com/posener/complete v1.2.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E=
|
||||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
|
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
|
||||||
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
|
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
|
||||||
|
github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4=
|
||||||
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
|
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||||
github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0=
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
|
||||||
|
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||||
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||||
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
|
github.com/vmihailenco/msgpack v4.0.1+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||||
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
github.com/vmihailenco/msgpack/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvCazn8G65U=
|
||||||
github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
|
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
|
||||||
github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
|
github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY=
|
||||||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
|
||||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/zclconf/go-cty v1.13.2 h1:4GvrUxe/QUDYuJKAav4EYqdM47/kZa672LwmXFmEKT0=
|
github.com/zclconf/go-cty v1.0.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
|
||||||
github.com/zclconf/go-cty v1.13.2/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=
|
github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
|
||||||
|
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
|
||||||
|
github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
|
||||||
|
github.com/zclconf/go-cty v1.9.1/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
||||||
|
github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0=
|
||||||
|
github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
||||||
|
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
|
||||||
|
github.com/zclconf/go-cty-yaml v1.0.1 h1:up11wlgAaDvlAGENcFDnZgkn0qUJurso7k6EpURKNF8=
|
||||||
|
github.com/zclconf/go-cty-yaml v1.0.1/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0=
|
||||||
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
|
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
|
||||||
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
|
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
|
||||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
|
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
golang.org/x/net v0.0.0-20210326060303-6b1517762897 h1:KrsHThm5nFk34YtATK1LsThyGhGbGe1olrte/HInHvs=
|
||||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
|
||||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
||||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
|
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.9.0 h1:jbyannxz0XFD3zdjgrSUsaJbgpH4eTrkdhRChkHPfO8=
|
||||||
|
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||||
google.golang.org/grpc v1.56.0 h1:+y7Bs8rtMd07LeXmL3NxcTLn7mUkbKZqEpPhMNkwJEE=
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
google.golang.org/grpc v1.56.0/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200310143817-43be25429f5a h1:lRlI5zu6AFy3iU/F8YWyNrAmn/tPCnhiTxfwhWb76eU=
|
||||||
|
google.golang.org/genproto v0.0.0-20200310143817-43be25429f5a/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
|
||||||
|
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||||
|
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
2
main.go
2
main.go
@ -2,7 +2,7 @@ package main // import "src.techknowlogick.com/terraform-provider-gitea"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.uploadfilter24.eu/terraform-provider-gitea/gitea"
|
"git.uploadfilter24.eu/terraform-provider-gitea/gitea"
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/plugin"
|
"github.com/hashicorp/terraform-plugin-sdk/plugin"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Version = "development"
|
var Version = "development"
|
||||||
|
@ -6,12 +6,11 @@ networks:
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
server:
|
server:
|
||||||
image: gitea/gitea:1.19.3
|
image: gitea/gitea:1.16.8
|
||||||
container_name: gitea
|
container_name: gitea
|
||||||
environment:
|
environment:
|
||||||
- USER_UID=1000
|
- USER_UID=1000
|
||||||
- USER_GID=1000
|
- USER_GID=1000
|
||||||
- DISABLE_GIT_HOOKS=false
|
|
||||||
restart: always
|
restart: always
|
||||||
networks:
|
networks:
|
||||||
- gitea
|
- gitea
|
||||||
|
202
vendor/cloud.google.com/go/LICENSE
generated
vendored
Normal file
202
vendor/cloud.google.com/go/LICENSE
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
526
vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
Normal file
526
vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
Normal file
@ -0,0 +1,526 @@
|
|||||||
|
// Copyright 2014 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package metadata provides access to Google Compute Engine (GCE)
|
||||||
|
// metadata and API service accounts.
|
||||||
|
//
|
||||||
|
// This package is a wrapper around the GCE metadata service,
|
||||||
|
// as documented at https://developers.google.com/compute/docs/metadata.
|
||||||
|
package metadata // import "cloud.google.com/go/compute/metadata"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// metadataIP is the documented metadata server IP address.
|
||||||
|
metadataIP = "169.254.169.254"
|
||||||
|
|
||||||
|
// metadataHostEnv is the environment variable specifying the
|
||||||
|
// GCE metadata hostname. If empty, the default value of
|
||||||
|
// metadataIP ("169.254.169.254") is used instead.
|
||||||
|
// This is variable name is not defined by any spec, as far as
|
||||||
|
// I know; it was made up for the Go package.
|
||||||
|
metadataHostEnv = "GCE_METADATA_HOST"
|
||||||
|
|
||||||
|
userAgent = "gcloud-golang/0.1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type cachedValue struct {
|
||||||
|
k string
|
||||||
|
trim bool
|
||||||
|
mu sync.Mutex
|
||||||
|
v string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
projID = &cachedValue{k: "project/project-id", trim: true}
|
||||||
|
projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
|
||||||
|
instID = &cachedValue{k: "instance/id", trim: true}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
defaultClient = &Client{hc: &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
Dial: (&net.Dialer{
|
||||||
|
Timeout: 2 * time.Second,
|
||||||
|
KeepAlive: 30 * time.Second,
|
||||||
|
}).Dial,
|
||||||
|
ResponseHeaderTimeout: 2 * time.Second,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
subscribeClient = &Client{hc: &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
Dial: (&net.Dialer{
|
||||||
|
Timeout: 2 * time.Second,
|
||||||
|
KeepAlive: 30 * time.Second,
|
||||||
|
}).Dial,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
)
|
||||||
|
|
||||||
|
// NotDefinedError is returned when requested metadata is not defined.
|
||||||
|
//
|
||||||
|
// The underlying string is the suffix after "/computeMetadata/v1/".
|
||||||
|
//
|
||||||
|
// This error is not returned if the value is defined to be the empty
|
||||||
|
// string.
|
||||||
|
type NotDefinedError string
|
||||||
|
|
||||||
|
func (suffix NotDefinedError) Error() string {
|
||||||
|
return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cachedValue) get(cl *Client) (v string, err error) {
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
c.mu.Lock()
|
||||||
|
if c.v != "" {
|
||||||
|
return c.v, nil
|
||||||
|
}
|
||||||
|
if c.trim {
|
||||||
|
v, err = cl.getTrimmed(c.k)
|
||||||
|
} else {
|
||||||
|
v, err = cl.Get(c.k)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
c.v = v
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
onGCEOnce sync.Once
|
||||||
|
onGCE bool
|
||||||
|
)
|
||||||
|
|
||||||
|
// OnGCE reports whether this process is running on Google Compute Engine.
|
||||||
|
func OnGCE() bool {
|
||||||
|
onGCEOnce.Do(initOnGCE)
|
||||||
|
return onGCE
|
||||||
|
}
|
||||||
|
|
||||||
|
func initOnGCE() {
|
||||||
|
onGCE = testOnGCE()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testOnGCE() bool {
|
||||||
|
// The user explicitly said they're on GCE, so trust them.
|
||||||
|
if os.Getenv(metadataHostEnv) != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
resc := make(chan bool, 2)
|
||||||
|
|
||||||
|
// Try two strategies in parallel.
|
||||||
|
// See https://github.com/googleapis/google-cloud-go/issues/194
|
||||||
|
go func() {
|
||||||
|
req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
|
||||||
|
req.Header.Set("User-Agent", userAgent)
|
||||||
|
res, err := defaultClient.hc.Do(req.WithContext(ctx))
|
||||||
|
if err != nil {
|
||||||
|
resc <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
resc <- res.Header.Get("Metadata-Flavor") == "Google"
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
addrs, err := net.LookupHost("metadata.google.internal")
|
||||||
|
if err != nil || len(addrs) == 0 {
|
||||||
|
resc <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resc <- strsContains(addrs, metadataIP)
|
||||||
|
}()
|
||||||
|
|
||||||
|
tryHarder := systemInfoSuggestsGCE()
|
||||||
|
if tryHarder {
|
||||||
|
res := <-resc
|
||||||
|
if res {
|
||||||
|
// The first strategy succeeded, so let's use it.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// Wait for either the DNS or metadata server probe to
|
||||||
|
// contradict the other one and say we are running on
|
||||||
|
// GCE. Give it a lot of time to do so, since the system
|
||||||
|
// info already suggests we're running on a GCE BIOS.
|
||||||
|
timer := time.NewTimer(5 * time.Second)
|
||||||
|
defer timer.Stop()
|
||||||
|
select {
|
||||||
|
case res = <-resc:
|
||||||
|
return res
|
||||||
|
case <-timer.C:
|
||||||
|
// Too slow. Who knows what this system is.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// There's no hint from the system info that we're running on
|
||||||
|
// GCE, so use the first probe's result as truth, whether it's
|
||||||
|
// true or false. The goal here is to optimize for speed for
|
||||||
|
// users who are NOT running on GCE. We can't assume that
|
||||||
|
// either a DNS lookup or an HTTP request to a blackholed IP
|
||||||
|
// address is fast. Worst case this should return when the
|
||||||
|
// metaClient's Transport.ResponseHeaderTimeout or
|
||||||
|
// Transport.Dial.Timeout fires (in two seconds).
|
||||||
|
return <-resc
|
||||||
|
}
|
||||||
|
|
||||||
|
// systemInfoSuggestsGCE reports whether the local system (without
|
||||||
|
// doing network requests) suggests that we're running on GCE. If this
|
||||||
|
// returns true, testOnGCE tries a bit harder to reach its metadata
|
||||||
|
// server.
|
||||||
|
func systemInfoSuggestsGCE() bool {
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
// We don't have any non-Linux clues available, at least yet.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
slurp, _ := ioutil.ReadFile("/sys/class/dmi/id/product_name")
|
||||||
|
name := strings.TrimSpace(string(slurp))
|
||||||
|
return name == "Google" || name == "Google Compute Engine"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe calls Client.Subscribe on a client designed for subscribing (one with no
|
||||||
|
// ResponseHeaderTimeout).
|
||||||
|
func Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||||
|
return subscribeClient.Subscribe(suffix, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get calls Client.Get on the default client.
|
||||||
|
func Get(suffix string) (string, error) { return defaultClient.Get(suffix) }
|
||||||
|
|
||||||
|
// ProjectID returns the current instance's project ID string.
|
||||||
|
func ProjectID() (string, error) { return defaultClient.ProjectID() }
|
||||||
|
|
||||||
|
// NumericProjectID returns the current instance's numeric project ID.
|
||||||
|
func NumericProjectID() (string, error) { return defaultClient.NumericProjectID() }
|
||||||
|
|
||||||
|
// InternalIP returns the instance's primary internal IP address.
|
||||||
|
func InternalIP() (string, error) { return defaultClient.InternalIP() }
|
||||||
|
|
||||||
|
// ExternalIP returns the instance's primary external (public) IP address.
|
||||||
|
func ExternalIP() (string, error) { return defaultClient.ExternalIP() }
|
||||||
|
|
||||||
|
// Email calls Client.Email on the default client.
|
||||||
|
func Email(serviceAccount string) (string, error) { return defaultClient.Email(serviceAccount) }
|
||||||
|
|
||||||
|
// Hostname returns the instance's hostname. This will be of the form
|
||||||
|
// "<instanceID>.c.<projID>.internal".
|
||||||
|
func Hostname() (string, error) { return defaultClient.Hostname() }
|
||||||
|
|
||||||
|
// InstanceTags returns the list of user-defined instance tags,
|
||||||
|
// assigned when initially creating a GCE instance.
|
||||||
|
func InstanceTags() ([]string, error) { return defaultClient.InstanceTags() }
|
||||||
|
|
||||||
|
// InstanceID returns the current VM's numeric instance ID.
|
||||||
|
func InstanceID() (string, error) { return defaultClient.InstanceID() }
|
||||||
|
|
||||||
|
// InstanceName returns the current VM's instance ID string.
|
||||||
|
func InstanceName() (string, error) { return defaultClient.InstanceName() }
|
||||||
|
|
||||||
|
// Zone returns the current VM's zone, such as "us-central1-b".
|
||||||
|
func Zone() (string, error) { return defaultClient.Zone() }
|
||||||
|
|
||||||
|
// InstanceAttributes calls Client.InstanceAttributes on the default client.
|
||||||
|
func InstanceAttributes() ([]string, error) { return defaultClient.InstanceAttributes() }
|
||||||
|
|
||||||
|
// ProjectAttributes calls Client.ProjectAttributes on the default client.
|
||||||
|
func ProjectAttributes() ([]string, error) { return defaultClient.ProjectAttributes() }
|
||||||
|
|
||||||
|
// InstanceAttributeValue calls Client.InstanceAttributeValue on the default client.
|
||||||
|
func InstanceAttributeValue(attr string) (string, error) {
|
||||||
|
return defaultClient.InstanceAttributeValue(attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectAttributeValue calls Client.ProjectAttributeValue on the default client.
|
||||||
|
func ProjectAttributeValue(attr string) (string, error) {
|
||||||
|
return defaultClient.ProjectAttributeValue(attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scopes calls Client.Scopes on the default client.
|
||||||
|
func Scopes(serviceAccount string) ([]string, error) { return defaultClient.Scopes(serviceAccount) }
|
||||||
|
|
||||||
|
func strsContains(ss []string, s string) bool {
|
||||||
|
for _, v := range ss {
|
||||||
|
if v == s {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Client provides metadata.
|
||||||
|
type Client struct {
|
||||||
|
hc *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns a Client that can be used to fetch metadata. All HTTP requests
|
||||||
|
// will use the given http.Client instead of the default client.
|
||||||
|
func NewClient(c *http.Client) *Client {
|
||||||
|
return &Client{hc: c}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getETag returns a value from the metadata service as well as the associated ETag.
|
||||||
|
// This func is otherwise equivalent to Get.
|
||||||
|
func (c *Client) getETag(suffix string) (value, etag string, err error) {
|
||||||
|
// Using a fixed IP makes it very difficult to spoof the metadata service in
|
||||||
|
// a container, which is an important use-case for local testing of cloud
|
||||||
|
// deployments. To enable spoofing of the metadata service, the environment
|
||||||
|
// variable GCE_METADATA_HOST is first inspected to decide where metadata
|
||||||
|
// requests shall go.
|
||||||
|
host := os.Getenv(metadataHostEnv)
|
||||||
|
if host == "" {
|
||||||
|
// Using 169.254.169.254 instead of "metadata" here because Go
|
||||||
|
// binaries built with the "netgo" tag and without cgo won't
|
||||||
|
// know the search suffix for "metadata" is
|
||||||
|
// ".google.internal", and this IP address is documented as
|
||||||
|
// being stable anyway.
|
||||||
|
host = metadataIP
|
||||||
|
}
|
||||||
|
u := "http://" + host + "/computeMetadata/v1/" + suffix
|
||||||
|
req, _ := http.NewRequest("GET", u, nil)
|
||||||
|
req.Header.Set("Metadata-Flavor", "Google")
|
||||||
|
req.Header.Set("User-Agent", userAgent)
|
||||||
|
res, err := c.hc.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
if res.StatusCode == http.StatusNotFound {
|
||||||
|
return "", "", NotDefinedError(suffix)
|
||||||
|
}
|
||||||
|
all, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
if res.StatusCode != 200 {
|
||||||
|
return "", "", &Error{Code: res.StatusCode, Message: string(all)}
|
||||||
|
}
|
||||||
|
return string(all), res.Header.Get("Etag"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns a value from the metadata service.
|
||||||
|
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||||
|
//
|
||||||
|
// If the GCE_METADATA_HOST environment variable is not defined, a default of
|
||||||
|
// 169.254.169.254 will be used instead.
|
||||||
|
//
|
||||||
|
// If the requested metadata is not defined, the returned error will
|
||||||
|
// be of type NotDefinedError.
|
||||||
|
func (c *Client) Get(suffix string) (string, error) {
|
||||||
|
val, _, err := c.getETag(suffix)
|
||||||
|
return val, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getTrimmed(suffix string) (s string, err error) {
|
||||||
|
s, err = c.Get(suffix)
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) lines(suffix string) ([]string, error) {
|
||||||
|
j, err := c.Get(suffix)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s := strings.Split(strings.TrimSpace(j), "\n")
|
||||||
|
for i := range s {
|
||||||
|
s[i] = strings.TrimSpace(s[i])
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectID returns the current instance's project ID string.
|
||||||
|
func (c *Client) ProjectID() (string, error) { return projID.get(c) }
|
||||||
|
|
||||||
|
// NumericProjectID returns the current instance's numeric project ID.
|
||||||
|
func (c *Client) NumericProjectID() (string, error) { return projNum.get(c) }
|
||||||
|
|
||||||
|
// InstanceID returns the current VM's numeric instance ID.
|
||||||
|
func (c *Client) InstanceID() (string, error) { return instID.get(c) }
|
||||||
|
|
||||||
|
// InternalIP returns the instance's primary internal IP address.
|
||||||
|
func (c *Client) InternalIP() (string, error) {
|
||||||
|
return c.getTrimmed("instance/network-interfaces/0/ip")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Email returns the email address associated with the service account.
|
||||||
|
// The account may be empty or the string "default" to use the instance's
|
||||||
|
// main account.
|
||||||
|
func (c *Client) Email(serviceAccount string) (string, error) {
|
||||||
|
if serviceAccount == "" {
|
||||||
|
serviceAccount = "default"
|
||||||
|
}
|
||||||
|
return c.getTrimmed("instance/service-accounts/" + serviceAccount + "/email")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExternalIP returns the instance's primary external (public) IP address.
|
||||||
|
func (c *Client) ExternalIP() (string, error) {
|
||||||
|
return c.getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hostname returns the instance's hostname. This will be of the form
|
||||||
|
// "<instanceID>.c.<projID>.internal".
|
||||||
|
func (c *Client) Hostname() (string, error) {
|
||||||
|
return c.getTrimmed("instance/hostname")
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceTags returns the list of user-defined instance tags,
|
||||||
|
// assigned when initially creating a GCE instance.
|
||||||
|
func (c *Client) InstanceTags() ([]string, error) {
|
||||||
|
var s []string
|
||||||
|
j, err := c.Get("instance/tags")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceName returns the current VM's instance ID string.
|
||||||
|
func (c *Client) InstanceName() (string, error) {
|
||||||
|
host, err := c.Hostname()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return strings.Split(host, ".")[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zone returns the current VM's zone, such as "us-central1-b".
|
||||||
|
func (c *Client) Zone() (string, error) {
|
||||||
|
zone, err := c.getTrimmed("instance/zone")
|
||||||
|
// zone is of the form "projects/<projNum>/zones/<zoneName>".
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return zone[strings.LastIndex(zone, "/")+1:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceAttributes returns the list of user-defined attributes,
|
||||||
|
// assigned when initially creating a GCE VM instance. The value of an
|
||||||
|
// attribute can be obtained with InstanceAttributeValue.
|
||||||
|
func (c *Client) InstanceAttributes() ([]string, error) { return c.lines("instance/attributes/") }
|
||||||
|
|
||||||
|
// ProjectAttributes returns the list of user-defined attributes
|
||||||
|
// applying to the project as a whole, not just this VM. The value of
|
||||||
|
// an attribute can be obtained with ProjectAttributeValue.
|
||||||
|
func (c *Client) ProjectAttributes() ([]string, error) { return c.lines("project/attributes/") }
|
||||||
|
|
||||||
|
// InstanceAttributeValue returns the value of the provided VM
|
||||||
|
// instance attribute.
|
||||||
|
//
|
||||||
|
// If the requested attribute is not defined, the returned error will
|
||||||
|
// be of type NotDefinedError.
|
||||||
|
//
|
||||||
|
// InstanceAttributeValue may return ("", nil) if the attribute was
|
||||||
|
// defined to be the empty string.
|
||||||
|
func (c *Client) InstanceAttributeValue(attr string) (string, error) {
|
||||||
|
return c.Get("instance/attributes/" + attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectAttributeValue returns the value of the provided
|
||||||
|
// project attribute.
|
||||||
|
//
|
||||||
|
// If the requested attribute is not defined, the returned error will
|
||||||
|
// be of type NotDefinedError.
|
||||||
|
//
|
||||||
|
// ProjectAttributeValue may return ("", nil) if the attribute was
|
||||||
|
// defined to be the empty string.
|
||||||
|
func (c *Client) ProjectAttributeValue(attr string) (string, error) {
|
||||||
|
return c.Get("project/attributes/" + attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scopes returns the service account scopes for the given account.
|
||||||
|
// The account may be empty or the string "default" to use the instance's
|
||||||
|
// main account.
|
||||||
|
func (c *Client) Scopes(serviceAccount string) ([]string, error) {
|
||||||
|
if serviceAccount == "" {
|
||||||
|
serviceAccount = "default"
|
||||||
|
}
|
||||||
|
return c.lines("instance/service-accounts/" + serviceAccount + "/scopes")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe subscribes to a value from the metadata service.
|
||||||
|
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||||
|
// The suffix may contain query parameters.
|
||||||
|
//
|
||||||
|
// Subscribe calls fn with the latest metadata value indicated by the provided
|
||||||
|
// suffix. If the metadata value is deleted, fn is called with the empty string
|
||||||
|
// and ok false. Subscribe blocks until fn returns a non-nil error or the value
|
||||||
|
// is deleted. Subscribe returns the error value returned from the last call to
|
||||||
|
// fn, which may be nil when ok == false.
|
||||||
|
func (c *Client) Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||||
|
const failedSubscribeSleep = time.Second * 5
|
||||||
|
|
||||||
|
// First check to see if the metadata value exists at all.
|
||||||
|
val, lastETag, err := c.getETag(suffix)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := fn(val, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ok := true
|
||||||
|
if strings.ContainsRune(suffix, '?') {
|
||||||
|
suffix += "&wait_for_change=true&last_etag="
|
||||||
|
} else {
|
||||||
|
suffix += "?wait_for_change=true&last_etag="
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
val, etag, err := c.getETag(suffix + url.QueryEscape(lastETag))
|
||||||
|
if err != nil {
|
||||||
|
if _, deleted := err.(NotDefinedError); !deleted {
|
||||||
|
time.Sleep(failedSubscribeSleep)
|
||||||
|
continue // Retry on other errors.
|
||||||
|
}
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
lastETag = etag
|
||||||
|
|
||||||
|
if err := fn(val, ok); err != nil || !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error contains an error response from the server.
|
||||||
|
type Error struct {
|
||||||
|
// Code is the HTTP response status code.
|
||||||
|
Code int
|
||||||
|
// Message is the server response message.
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
return fmt.Sprintf("compute: Received %d `%s`", e.Code, e.Message)
|
||||||
|
}
|
315
vendor/cloud.google.com/go/iam/iam.go
generated
vendored
Normal file
315
vendor/cloud.google.com/go/iam/iam.go
generated
vendored
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
// Copyright 2016 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package iam supports the resource-specific operations of Google Cloud
|
||||||
|
// IAM (Identity and Access Management) for the Google Cloud Libraries.
|
||||||
|
// See https://cloud.google.com/iam for more about IAM.
|
||||||
|
//
|
||||||
|
// Users of the Google Cloud Libraries will typically not use this package
|
||||||
|
// directly. Instead they will begin with some resource that supports IAM, like
|
||||||
|
// a pubsub topic, and call its IAM method to get a Handle for that resource.
|
||||||
|
package iam
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
gax "github.com/googleapis/gax-go/v2"
|
||||||
|
pb "google.golang.org/genproto/googleapis/iam/v1"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
// client abstracts the IAMPolicy API to allow multiple implementations.
|
||||||
|
type client interface {
|
||||||
|
Get(ctx context.Context, resource string) (*pb.Policy, error)
|
||||||
|
Set(ctx context.Context, resource string, p *pb.Policy) error
|
||||||
|
Test(ctx context.Context, resource string, perms []string) ([]string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// grpcClient implements client for the standard gRPC-based IAMPolicy service.
|
||||||
|
type grpcClient struct {
|
||||||
|
c pb.IAMPolicyClient
|
||||||
|
}
|
||||||
|
|
||||||
|
var withRetry = gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 60 * time.Second,
|
||||||
|
Multiplier: 1.3,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
func (g *grpcClient) Get(ctx context.Context, resource string) (*pb.Policy, error) {
|
||||||
|
var proto *pb.Policy
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", resource))
|
||||||
|
ctx = insertMetadata(ctx, md)
|
||||||
|
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
proto, err = g.c.GetIamPolicy(ctx, &pb.GetIamPolicyRequest{Resource: resource})
|
||||||
|
return err
|
||||||
|
}, withRetry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return proto, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *grpcClient) Set(ctx context.Context, resource string, p *pb.Policy) error {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", resource))
|
||||||
|
ctx = insertMetadata(ctx, md)
|
||||||
|
|
||||||
|
return gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error {
|
||||||
|
_, err := g.c.SetIamPolicy(ctx, &pb.SetIamPolicyRequest{
|
||||||
|
Resource: resource,
|
||||||
|
Policy: p,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}, withRetry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *grpcClient) Test(ctx context.Context, resource string, perms []string) ([]string, error) {
|
||||||
|
var res *pb.TestIamPermissionsResponse
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", resource))
|
||||||
|
ctx = insertMetadata(ctx, md)
|
||||||
|
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
res, err = g.c.TestIamPermissions(ctx, &pb.TestIamPermissionsRequest{
|
||||||
|
Resource: resource,
|
||||||
|
Permissions: perms,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}, withRetry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res.Permissions, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Handle provides IAM operations for a resource.
|
||||||
|
type Handle struct {
|
||||||
|
c client
|
||||||
|
resource string
|
||||||
|
}
|
||||||
|
|
||||||
|
// InternalNewHandle is for use by the Google Cloud Libraries only.
|
||||||
|
//
|
||||||
|
// InternalNewHandle returns a Handle for resource.
|
||||||
|
// The conn parameter refers to a server that must support the IAMPolicy service.
|
||||||
|
func InternalNewHandle(conn *grpc.ClientConn, resource string) *Handle {
|
||||||
|
return InternalNewHandleGRPCClient(pb.NewIAMPolicyClient(conn), resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InternalNewHandleGRPCClient is for use by the Google Cloud Libraries only.
|
||||||
|
//
|
||||||
|
// InternalNewHandleClient returns a Handle for resource using the given
|
||||||
|
// grpc service that implements IAM as a mixin
|
||||||
|
func InternalNewHandleGRPCClient(c pb.IAMPolicyClient, resource string) *Handle {
|
||||||
|
return InternalNewHandleClient(&grpcClient{c: c}, resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InternalNewHandleClient is for use by the Google Cloud Libraries only.
|
||||||
|
//
|
||||||
|
// InternalNewHandleClient returns a Handle for resource using the given
|
||||||
|
// client implementation.
|
||||||
|
func InternalNewHandleClient(c client, resource string) *Handle {
|
||||||
|
return &Handle{
|
||||||
|
c: c,
|
||||||
|
resource: resource,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Policy retrieves the IAM policy for the resource.
|
||||||
|
func (h *Handle) Policy(ctx context.Context) (*Policy, error) {
|
||||||
|
proto, err := h.c.Get(ctx, h.resource)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Policy{InternalProto: proto}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPolicy replaces the resource's current policy with the supplied Policy.
|
||||||
|
//
|
||||||
|
// If policy was created from a prior call to Get, then the modification will
|
||||||
|
// only succeed if the policy has not changed since the Get.
|
||||||
|
func (h *Handle) SetPolicy(ctx context.Context, policy *Policy) error {
|
||||||
|
return h.c.Set(ctx, h.resource, policy.InternalProto)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestPermissions returns the subset of permissions that the caller has on the resource.
|
||||||
|
func (h *Handle) TestPermissions(ctx context.Context, permissions []string) ([]string, error) {
|
||||||
|
return h.c.Test(ctx, h.resource, permissions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A RoleName is a name representing a collection of permissions.
|
||||||
|
type RoleName string
|
||||||
|
|
||||||
|
// Common role names.
|
||||||
|
const (
|
||||||
|
Owner RoleName = "roles/owner"
|
||||||
|
Editor RoleName = "roles/editor"
|
||||||
|
Viewer RoleName = "roles/viewer"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AllUsers is a special member that denotes all users, even unauthenticated ones.
|
||||||
|
AllUsers = "allUsers"
|
||||||
|
|
||||||
|
// AllAuthenticatedUsers is a special member that denotes all authenticated users.
|
||||||
|
AllAuthenticatedUsers = "allAuthenticatedUsers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Policy is a list of Bindings representing roles
|
||||||
|
// granted to members.
|
||||||
|
//
|
||||||
|
// The zero Policy is a valid policy with no bindings.
|
||||||
|
type Policy struct {
|
||||||
|
// TODO(jba): when type aliases are available, put Policy into an internal package
|
||||||
|
// and provide an exported alias here.
|
||||||
|
|
||||||
|
// This field is exported for use by the Google Cloud Libraries only.
|
||||||
|
// It may become unexported in a future release.
|
||||||
|
InternalProto *pb.Policy
|
||||||
|
}
|
||||||
|
|
||||||
|
// Members returns the list of members with the supplied role.
|
||||||
|
// The return value should not be modified. Use Add and Remove
|
||||||
|
// to modify the members of a role.
|
||||||
|
func (p *Policy) Members(r RoleName) []string {
|
||||||
|
b := p.binding(r)
|
||||||
|
if b == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return b.Members
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasRole reports whether member has role r.
|
||||||
|
func (p *Policy) HasRole(member string, r RoleName) bool {
|
||||||
|
return memberIndex(member, p.binding(r)) >= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds member member to role r if it is not already present.
|
||||||
|
// A new binding is created if there is no binding for the role.
|
||||||
|
func (p *Policy) Add(member string, r RoleName) {
|
||||||
|
b := p.binding(r)
|
||||||
|
if b == nil {
|
||||||
|
if p.InternalProto == nil {
|
||||||
|
p.InternalProto = &pb.Policy{}
|
||||||
|
}
|
||||||
|
p.InternalProto.Bindings = append(p.InternalProto.Bindings, &pb.Binding{
|
||||||
|
Role: string(r),
|
||||||
|
Members: []string{member},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if memberIndex(member, b) < 0 {
|
||||||
|
b.Members = append(b.Members, member)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove removes member from role r if it is present.
|
||||||
|
func (p *Policy) Remove(member string, r RoleName) {
|
||||||
|
bi := p.bindingIndex(r)
|
||||||
|
if bi < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bindings := p.InternalProto.Bindings
|
||||||
|
b := bindings[bi]
|
||||||
|
mi := memberIndex(member, b)
|
||||||
|
if mi < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Order doesn't matter for bindings or members, so to remove, move the last item
|
||||||
|
// into the removed spot and shrink the slice.
|
||||||
|
if len(b.Members) == 1 {
|
||||||
|
// Remove binding.
|
||||||
|
last := len(bindings) - 1
|
||||||
|
bindings[bi] = bindings[last]
|
||||||
|
bindings[last] = nil
|
||||||
|
p.InternalProto.Bindings = bindings[:last]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Remove member.
|
||||||
|
// TODO(jba): worry about multiple copies of m?
|
||||||
|
last := len(b.Members) - 1
|
||||||
|
b.Members[mi] = b.Members[last]
|
||||||
|
b.Members[last] = ""
|
||||||
|
b.Members = b.Members[:last]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Roles returns the names of all the roles that appear in the Policy.
|
||||||
|
func (p *Policy) Roles() []RoleName {
|
||||||
|
if p.InternalProto == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var rns []RoleName
|
||||||
|
for _, b := range p.InternalProto.Bindings {
|
||||||
|
rns = append(rns, RoleName(b.Role))
|
||||||
|
}
|
||||||
|
return rns
|
||||||
|
}
|
||||||
|
|
||||||
|
// binding returns the Binding for the suppied role, or nil if there isn't one.
|
||||||
|
func (p *Policy) binding(r RoleName) *pb.Binding {
|
||||||
|
i := p.bindingIndex(r)
|
||||||
|
if i < 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return p.InternalProto.Bindings[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Policy) bindingIndex(r RoleName) int {
|
||||||
|
if p.InternalProto == nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
for i, b := range p.InternalProto.Bindings {
|
||||||
|
if b.Role == string(r) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// memberIndex returns the index of m in b's Members, or -1 if not found.
|
||||||
|
func memberIndex(m string, b *pb.Binding) int {
|
||||||
|
if b == nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
for i, mm := range b.Members {
|
||||||
|
if mm == m {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// insertMetadata inserts metadata into the given context
|
||||||
|
func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context {
|
||||||
|
out, _ := metadata.FromOutgoingContext(ctx)
|
||||||
|
out = out.Copy()
|
||||||
|
for _, md := range mds {
|
||||||
|
for k, v := range md {
|
||||||
|
out[k] = append(out[k], v...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return metadata.NewOutgoingContext(ctx, out)
|
||||||
|
}
|
54
vendor/cloud.google.com/go/internal/annotate.go
generated
vendored
Normal file
54
vendor/cloud.google.com/go/internal/annotate.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"google.golang.org/api/googleapi"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Annotate prepends msg to the error message in err, attempting
|
||||||
|
// to preserve other information in err, like an error code.
|
||||||
|
//
|
||||||
|
// Annotate panics if err is nil.
|
||||||
|
//
|
||||||
|
// Annotate knows about these error types:
|
||||||
|
// - "google.golang.org/grpc/status".Status
|
||||||
|
// - "google.golang.org/api/googleapi".Error
|
||||||
|
// If the error is not one of these types, Annotate behaves
|
||||||
|
// like
|
||||||
|
// fmt.Errorf("%s: %v", msg, err)
|
||||||
|
func Annotate(err error, msg string) error {
|
||||||
|
if err == nil {
|
||||||
|
panic("Annotate called with nil")
|
||||||
|
}
|
||||||
|
if s, ok := status.FromError(err); ok {
|
||||||
|
p := s.Proto()
|
||||||
|
p.Message = msg + ": " + p.Message
|
||||||
|
return status.ErrorProto(p)
|
||||||
|
}
|
||||||
|
if g, ok := err.(*googleapi.Error); ok {
|
||||||
|
g.Message = msg + ": " + g.Message
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
return fmt.Errorf("%s: %v", msg, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Annotatef uses format and args to format a string, then calls Annotate.
|
||||||
|
func Annotatef(err error, format string, args ...interface{}) error {
|
||||||
|
return Annotate(err, fmt.Sprintf(format, args...))
|
||||||
|
}
|
108
vendor/cloud.google.com/go/internal/optional/optional.go
generated
vendored
Normal file
108
vendor/cloud.google.com/go/internal/optional/optional.go
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
// Copyright 2016 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package optional provides versions of primitive types that can
|
||||||
|
// be nil. These are useful in methods that update some of an API object's
|
||||||
|
// fields.
|
||||||
|
package optional
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Bool is either a bool or nil.
|
||||||
|
Bool interface{}
|
||||||
|
|
||||||
|
// String is either a string or nil.
|
||||||
|
String interface{}
|
||||||
|
|
||||||
|
// Int is either an int or nil.
|
||||||
|
Int interface{}
|
||||||
|
|
||||||
|
// Uint is either a uint or nil.
|
||||||
|
Uint interface{}
|
||||||
|
|
||||||
|
// Float64 is either a float64 or nil.
|
||||||
|
Float64 interface{}
|
||||||
|
|
||||||
|
// Duration is either a time.Duration or nil.
|
||||||
|
Duration interface{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// ToBool returns its argument as a bool.
|
||||||
|
// It panics if its argument is nil or not a bool.
|
||||||
|
func ToBool(v Bool) bool {
|
||||||
|
x, ok := v.(bool)
|
||||||
|
if !ok {
|
||||||
|
doPanic("Bool", v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToString returns its argument as a string.
|
||||||
|
// It panics if its argument is nil or not a string.
|
||||||
|
func ToString(v String) string {
|
||||||
|
x, ok := v.(string)
|
||||||
|
if !ok {
|
||||||
|
doPanic("String", v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToInt returns its argument as an int.
|
||||||
|
// It panics if its argument is nil or not an int.
|
||||||
|
func ToInt(v Int) int {
|
||||||
|
x, ok := v.(int)
|
||||||
|
if !ok {
|
||||||
|
doPanic("Int", v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToUint returns its argument as a uint.
|
||||||
|
// It panics if its argument is nil or not a uint.
|
||||||
|
func ToUint(v Uint) uint {
|
||||||
|
x, ok := v.(uint)
|
||||||
|
if !ok {
|
||||||
|
doPanic("Uint", v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFloat64 returns its argument as a float64.
|
||||||
|
// It panics if its argument is nil or not a float64.
|
||||||
|
func ToFloat64(v Float64) float64 {
|
||||||
|
x, ok := v.(float64)
|
||||||
|
if !ok {
|
||||||
|
doPanic("Float64", v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToDuration returns its argument as a time.Duration.
|
||||||
|
// It panics if its argument is nil or not a time.Duration.
|
||||||
|
func ToDuration(v Duration) time.Duration {
|
||||||
|
x, ok := v.(time.Duration)
|
||||||
|
if !ok {
|
||||||
|
doPanic("Duration", v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func doPanic(capType string, v interface{}) {
|
||||||
|
panic(fmt.Sprintf("optional.%s value should be %s, got %T", capType, strings.ToLower(capType), v))
|
||||||
|
}
|
54
vendor/cloud.google.com/go/internal/retry.go
generated
vendored
Normal file
54
vendor/cloud.google.com/go/internal/retry.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2016 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
gax "github.com/googleapis/gax-go/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Retry calls the supplied function f repeatedly according to the provided
|
||||||
|
// backoff parameters. It returns when one of the following occurs:
|
||||||
|
// When f's first return value is true, Retry immediately returns with f's second
|
||||||
|
// return value.
|
||||||
|
// When the provided context is done, Retry returns with an error that
|
||||||
|
// includes both ctx.Error() and the last error returned by f.
|
||||||
|
func Retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error)) error {
|
||||||
|
return retry(ctx, bo, f, gax.Sleep)
|
||||||
|
}
|
||||||
|
|
||||||
|
func retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error),
|
||||||
|
sleep func(context.Context, time.Duration) error) error {
|
||||||
|
var lastErr error
|
||||||
|
for {
|
||||||
|
stop, err := f()
|
||||||
|
if stop {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Remember the last "real" error from f.
|
||||||
|
if err != nil && err != context.Canceled && err != context.DeadlineExceeded {
|
||||||
|
lastErr = err
|
||||||
|
}
|
||||||
|
p := bo.Pause()
|
||||||
|
if cerr := sleep(ctx, p); cerr != nil {
|
||||||
|
if lastErr != nil {
|
||||||
|
return Annotatef(lastErr, "retry failed with %v; last error", cerr)
|
||||||
|
}
|
||||||
|
return cerr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
109
vendor/cloud.google.com/go/internal/trace/trace.go
generated
vendored
Normal file
109
vendor/cloud.google.com/go/internal/trace/trace.go
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
// Copyright 2018 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package trace
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"go.opencensus.io/trace"
|
||||||
|
"google.golang.org/api/googleapi"
|
||||||
|
"google.golang.org/genproto/googleapis/rpc/code"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StartSpan adds a span to the trace with the given name.
|
||||||
|
func StartSpan(ctx context.Context, name string) context.Context {
|
||||||
|
ctx, _ = trace.StartSpan(ctx, name)
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// EndSpan ends a span with the given error.
|
||||||
|
func EndSpan(ctx context.Context, err error) {
|
||||||
|
span := trace.FromContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
span.SetStatus(toStatus(err))
|
||||||
|
}
|
||||||
|
span.End()
|
||||||
|
}
|
||||||
|
|
||||||
|
// toStatus interrogates an error and converts it to an appropriate
|
||||||
|
// OpenCensus status.
|
||||||
|
func toStatus(err error) trace.Status {
|
||||||
|
if err2, ok := err.(*googleapi.Error); ok {
|
||||||
|
return trace.Status{Code: httpStatusCodeToOCCode(err2.Code), Message: err2.Message}
|
||||||
|
} else if s, ok := status.FromError(err); ok {
|
||||||
|
return trace.Status{Code: int32(s.Code()), Message: s.Message()}
|
||||||
|
} else {
|
||||||
|
return trace.Status{Code: int32(code.Code_UNKNOWN), Message: err.Error()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(deklerk): switch to using OpenCensus function when it becomes available.
|
||||||
|
// Reference: https://github.com/googleapis/googleapis/blob/26b634d2724ac5dd30ae0b0cbfb01f07f2e4050e/google/rpc/code.proto
|
||||||
|
func httpStatusCodeToOCCode(httpStatusCode int) int32 {
|
||||||
|
switch httpStatusCode {
|
||||||
|
case 200:
|
||||||
|
return int32(code.Code_OK)
|
||||||
|
case 499:
|
||||||
|
return int32(code.Code_CANCELLED)
|
||||||
|
case 500:
|
||||||
|
return int32(code.Code_UNKNOWN) // Could also be Code_INTERNAL, Code_DATA_LOSS
|
||||||
|
case 400:
|
||||||
|
return int32(code.Code_INVALID_ARGUMENT) // Could also be Code_OUT_OF_RANGE
|
||||||
|
case 504:
|
||||||
|
return int32(code.Code_DEADLINE_EXCEEDED)
|
||||||
|
case 404:
|
||||||
|
return int32(code.Code_NOT_FOUND)
|
||||||
|
case 409:
|
||||||
|
return int32(code.Code_ALREADY_EXISTS) // Could also be Code_ABORTED
|
||||||
|
case 403:
|
||||||
|
return int32(code.Code_PERMISSION_DENIED)
|
||||||
|
case 401:
|
||||||
|
return int32(code.Code_UNAUTHENTICATED)
|
||||||
|
case 429:
|
||||||
|
return int32(code.Code_RESOURCE_EXHAUSTED)
|
||||||
|
case 501:
|
||||||
|
return int32(code.Code_UNIMPLEMENTED)
|
||||||
|
case 503:
|
||||||
|
return int32(code.Code_UNAVAILABLE)
|
||||||
|
default:
|
||||||
|
return int32(code.Code_UNKNOWN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: (odeke-em): perhaps just pass around spans due to the cost
|
||||||
|
// incurred from using trace.FromContext(ctx) yet we could avoid
|
||||||
|
// throwing away the work done by ctx, span := trace.StartSpan.
|
||||||
|
func TracePrintf(ctx context.Context, attrMap map[string]interface{}, format string, args ...interface{}) {
|
||||||
|
var attrs []trace.Attribute
|
||||||
|
for k, v := range attrMap {
|
||||||
|
var a trace.Attribute
|
||||||
|
switch v := v.(type) {
|
||||||
|
case string:
|
||||||
|
a = trace.StringAttribute(k, v)
|
||||||
|
case bool:
|
||||||
|
a = trace.BoolAttribute(k, v)
|
||||||
|
case int:
|
||||||
|
a = trace.Int64Attribute(k, int64(v))
|
||||||
|
case int64:
|
||||||
|
a = trace.Int64Attribute(k, v)
|
||||||
|
default:
|
||||||
|
a = trace.StringAttribute(k, fmt.Sprintf("%#v", v))
|
||||||
|
}
|
||||||
|
attrs = append(attrs, a)
|
||||||
|
}
|
||||||
|
trace.FromContext(ctx).Annotatef(attrs, format, args...)
|
||||||
|
}
|
19
vendor/cloud.google.com/go/internal/version/update_version.sh
generated
vendored
Normal file
19
vendor/cloud.google.com/go/internal/version/update_version.sh
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Copyright 2019 Google LLC
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
today=$(date +%Y%m%d)
|
||||||
|
|
||||||
|
sed -i -r -e 's/const Repo = "([0-9]{8})"/const Repo = "'$today'"/' $GOFILE
|
||||||
|
|
71
vendor/cloud.google.com/go/internal/version/version.go
generated
vendored
Normal file
71
vendor/cloud.google.com/go/internal/version/version.go
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// Copyright 2016 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
//go:generate ./update_version.sh
|
||||||
|
|
||||||
|
// Package version contains version information for Google Cloud Client
|
||||||
|
// Libraries for Go, as reported in request headers.
|
||||||
|
package version
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Repo is the current version of the client libraries in this
|
||||||
|
// repo. It should be a date in YYYYMMDD format.
|
||||||
|
const Repo = "20190802"
|
||||||
|
|
||||||
|
// Go returns the Go runtime version. The returned string
|
||||||
|
// has no whitespace.
|
||||||
|
func Go() string {
|
||||||
|
return goVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
var goVersion = goVer(runtime.Version())
|
||||||
|
|
||||||
|
const develPrefix = "devel +"
|
||||||
|
|
||||||
|
func goVer(s string) string {
|
||||||
|
if strings.HasPrefix(s, develPrefix) {
|
||||||
|
s = s[len(develPrefix):]
|
||||||
|
if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 {
|
||||||
|
s = s[:p]
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(s, "go1") {
|
||||||
|
s = s[2:]
|
||||||
|
var prerelease string
|
||||||
|
if p := strings.IndexFunc(s, notSemverRune); p >= 0 {
|
||||||
|
s, prerelease = s[:p], s[p:]
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(s, ".") {
|
||||||
|
s += "0"
|
||||||
|
} else if strings.Count(s, ".") < 2 {
|
||||||
|
s += ".0"
|
||||||
|
}
|
||||||
|
if prerelease != "" {
|
||||||
|
s += "-" + prerelease
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func notSemverRune(r rune) bool {
|
||||||
|
return !strings.ContainsRune("0123456789.", r)
|
||||||
|
}
|
32
vendor/cloud.google.com/go/storage/README.md
generated
vendored
Normal file
32
vendor/cloud.google.com/go/storage/README.md
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
## Cloud Storage [![GoDoc](https://godoc.org/cloud.google.com/go/storage?status.svg)](https://godoc.org/cloud.google.com/go/storage)
|
||||||
|
|
||||||
|
- [About Cloud Storage](https://cloud.google.com/storage/)
|
||||||
|
- [API documentation](https://cloud.google.com/storage/docs)
|
||||||
|
- [Go client documentation](https://godoc.org/cloud.google.com/go/storage)
|
||||||
|
- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/storage)
|
||||||
|
|
||||||
|
### Example Usage
|
||||||
|
|
||||||
|
First create a `storage.Client` to use throughout your application:
|
||||||
|
|
||||||
|
[snip]:# (storage-1)
|
||||||
|
```go
|
||||||
|
client, err := storage.NewClient(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
[snip]:# (storage-2)
|
||||||
|
```go
|
||||||
|
// Read the object1 from bucket.
|
||||||
|
rc, err := client.Bucket("bucket").Object("object1").NewReader(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer rc.Close()
|
||||||
|
body, err := ioutil.ReadAll(rc)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
```
|
335
vendor/cloud.google.com/go/storage/acl.go
generated
vendored
Normal file
335
vendor/cloud.google.com/go/storage/acl.go
generated
vendored
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
// Copyright 2014 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"cloud.google.com/go/internal/trace"
|
||||||
|
"google.golang.org/api/googleapi"
|
||||||
|
raw "google.golang.org/api/storage/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ACLRole is the level of access to grant.
|
||||||
|
type ACLRole string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RoleOwner ACLRole = "OWNER"
|
||||||
|
RoleReader ACLRole = "READER"
|
||||||
|
RoleWriter ACLRole = "WRITER"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ACLEntity refers to a user or group.
|
||||||
|
// They are sometimes referred to as grantees.
|
||||||
|
//
|
||||||
|
// It could be in the form of:
|
||||||
|
// "user-<userId>", "user-<email>", "group-<groupId>", "group-<email>",
|
||||||
|
// "domain-<domain>" and "project-team-<projectId>".
|
||||||
|
//
|
||||||
|
// Or one of the predefined constants: AllUsers, AllAuthenticatedUsers.
|
||||||
|
type ACLEntity string
|
||||||
|
|
||||||
|
const (
|
||||||
|
AllUsers ACLEntity = "allUsers"
|
||||||
|
AllAuthenticatedUsers ACLEntity = "allAuthenticatedUsers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ACLRule represents a grant for a role to an entity (user, group or team) for a
|
||||||
|
// Google Cloud Storage object or bucket.
|
||||||
|
type ACLRule struct {
|
||||||
|
Entity ACLEntity
|
||||||
|
EntityID string
|
||||||
|
Role ACLRole
|
||||||
|
Domain string
|
||||||
|
Email string
|
||||||
|
ProjectTeam *ProjectTeam
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectTeam is the project team associated with the entity, if any.
|
||||||
|
type ProjectTeam struct {
|
||||||
|
ProjectNumber string
|
||||||
|
Team string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ACLHandle provides operations on an access control list for a Google Cloud Storage bucket or object.
|
||||||
|
type ACLHandle struct {
|
||||||
|
c *Client
|
||||||
|
bucket string
|
||||||
|
object string
|
||||||
|
isDefault bool
|
||||||
|
userProject string // for requester-pays buckets
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete permanently deletes the ACL entry for the given entity.
|
||||||
|
func (a *ACLHandle) Delete(ctx context.Context, entity ACLEntity) (err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.Delete")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
if a.object != "" {
|
||||||
|
return a.objectDelete(ctx, entity)
|
||||||
|
}
|
||||||
|
if a.isDefault {
|
||||||
|
return a.bucketDefaultDelete(ctx, entity)
|
||||||
|
}
|
||||||
|
return a.bucketDelete(ctx, entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the role for the given entity.
|
||||||
|
func (a *ACLHandle) Set(ctx context.Context, entity ACLEntity, role ACLRole) (err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.Set")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
if a.object != "" {
|
||||||
|
return a.objectSet(ctx, entity, role, false)
|
||||||
|
}
|
||||||
|
if a.isDefault {
|
||||||
|
return a.objectSet(ctx, entity, role, true)
|
||||||
|
}
|
||||||
|
return a.bucketSet(ctx, entity, role)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List retrieves ACL entries.
|
||||||
|
func (a *ACLHandle) List(ctx context.Context) (rules []ACLRule, err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.List")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
if a.object != "" {
|
||||||
|
return a.objectList(ctx)
|
||||||
|
}
|
||||||
|
if a.isDefault {
|
||||||
|
return a.bucketDefaultList(ctx)
|
||||||
|
}
|
||||||
|
return a.bucketList(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ACLHandle) bucketDefaultList(ctx context.Context) ([]ACLRule, error) {
|
||||||
|
var acls *raw.ObjectAccessControls
|
||||||
|
var err error
|
||||||
|
err = runWithRetry(ctx, func() error {
|
||||||
|
req := a.c.raw.DefaultObjectAccessControls.List(a.bucket)
|
||||||
|
a.configureCall(ctx, req)
|
||||||
|
acls, err = req.Do()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return toObjectACLRules(acls.Items), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ACLHandle) bucketDefaultDelete(ctx context.Context, entity ACLEntity) error {
|
||||||
|
return runWithRetry(ctx, func() error {
|
||||||
|
req := a.c.raw.DefaultObjectAccessControls.Delete(a.bucket, string(entity))
|
||||||
|
a.configureCall(ctx, req)
|
||||||
|
return req.Do()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ACLHandle) bucketList(ctx context.Context) ([]ACLRule, error) {
|
||||||
|
var acls *raw.BucketAccessControls
|
||||||
|
var err error
|
||||||
|
err = runWithRetry(ctx, func() error {
|
||||||
|
req := a.c.raw.BucketAccessControls.List(a.bucket)
|
||||||
|
a.configureCall(ctx, req)
|
||||||
|
acls, err = req.Do()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return toBucketACLRules(acls.Items), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ACLHandle) bucketSet(ctx context.Context, entity ACLEntity, role ACLRole) error {
|
||||||
|
acl := &raw.BucketAccessControl{
|
||||||
|
Bucket: a.bucket,
|
||||||
|
Entity: string(entity),
|
||||||
|
Role: string(role),
|
||||||
|
}
|
||||||
|
err := runWithRetry(ctx, func() error {
|
||||||
|
req := a.c.raw.BucketAccessControls.Update(a.bucket, string(entity), acl)
|
||||||
|
a.configureCall(ctx, req)
|
||||||
|
_, err := req.Do()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ACLHandle) bucketDelete(ctx context.Context, entity ACLEntity) error {
|
||||||
|
return runWithRetry(ctx, func() error {
|
||||||
|
req := a.c.raw.BucketAccessControls.Delete(a.bucket, string(entity))
|
||||||
|
a.configureCall(ctx, req)
|
||||||
|
return req.Do()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ACLHandle) objectList(ctx context.Context) ([]ACLRule, error) {
|
||||||
|
var acls *raw.ObjectAccessControls
|
||||||
|
var err error
|
||||||
|
err = runWithRetry(ctx, func() error {
|
||||||
|
req := a.c.raw.ObjectAccessControls.List(a.bucket, a.object)
|
||||||
|
a.configureCall(ctx, req)
|
||||||
|
acls, err = req.Do()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return toObjectACLRules(acls.Items), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ACLHandle) objectSet(ctx context.Context, entity ACLEntity, role ACLRole, isBucketDefault bool) error {
|
||||||
|
type setRequest interface {
|
||||||
|
Do(opts ...googleapi.CallOption) (*raw.ObjectAccessControl, error)
|
||||||
|
Header() http.Header
|
||||||
|
}
|
||||||
|
|
||||||
|
acl := &raw.ObjectAccessControl{
|
||||||
|
Bucket: a.bucket,
|
||||||
|
Entity: string(entity),
|
||||||
|
Role: string(role),
|
||||||
|
}
|
||||||
|
var req setRequest
|
||||||
|
if isBucketDefault {
|
||||||
|
req = a.c.raw.DefaultObjectAccessControls.Update(a.bucket, string(entity), acl)
|
||||||
|
} else {
|
||||||
|
req = a.c.raw.ObjectAccessControls.Update(a.bucket, a.object, string(entity), acl)
|
||||||
|
}
|
||||||
|
a.configureCall(ctx, req)
|
||||||
|
return runWithRetry(ctx, func() error {
|
||||||
|
_, err := req.Do()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ACLHandle) objectDelete(ctx context.Context, entity ACLEntity) error {
|
||||||
|
return runWithRetry(ctx, func() error {
|
||||||
|
req := a.c.raw.ObjectAccessControls.Delete(a.bucket, a.object, string(entity))
|
||||||
|
a.configureCall(ctx, req)
|
||||||
|
return req.Do()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ACLHandle) configureCall(ctx context.Context, call interface{ Header() http.Header }) {
|
||||||
|
vc := reflect.ValueOf(call)
|
||||||
|
vc.MethodByName("Context").Call([]reflect.Value{reflect.ValueOf(ctx)})
|
||||||
|
if a.userProject != "" {
|
||||||
|
vc.MethodByName("UserProject").Call([]reflect.Value{reflect.ValueOf(a.userProject)})
|
||||||
|
}
|
||||||
|
setClientHeader(call.Header())
|
||||||
|
}
|
||||||
|
|
||||||
|
func toObjectACLRules(items []*raw.ObjectAccessControl) []ACLRule {
|
||||||
|
var rs []ACLRule
|
||||||
|
for _, item := range items {
|
||||||
|
rs = append(rs, toObjectACLRule(item))
|
||||||
|
}
|
||||||
|
return rs
|
||||||
|
}
|
||||||
|
|
||||||
|
func toBucketACLRules(items []*raw.BucketAccessControl) []ACLRule {
|
||||||
|
var rs []ACLRule
|
||||||
|
for _, item := range items {
|
||||||
|
rs = append(rs, toBucketACLRule(item))
|
||||||
|
}
|
||||||
|
return rs
|
||||||
|
}
|
||||||
|
|
||||||
|
func toObjectACLRule(a *raw.ObjectAccessControl) ACLRule {
|
||||||
|
return ACLRule{
|
||||||
|
Entity: ACLEntity(a.Entity),
|
||||||
|
EntityID: a.EntityId,
|
||||||
|
Role: ACLRole(a.Role),
|
||||||
|
Domain: a.Domain,
|
||||||
|
Email: a.Email,
|
||||||
|
ProjectTeam: toObjectProjectTeam(a.ProjectTeam),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toBucketACLRule(a *raw.BucketAccessControl) ACLRule {
|
||||||
|
return ACLRule{
|
||||||
|
Entity: ACLEntity(a.Entity),
|
||||||
|
EntityID: a.EntityId,
|
||||||
|
Role: ACLRole(a.Role),
|
||||||
|
Domain: a.Domain,
|
||||||
|
Email: a.Email,
|
||||||
|
ProjectTeam: toBucketProjectTeam(a.ProjectTeam),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toRawObjectACL(rules []ACLRule) []*raw.ObjectAccessControl {
|
||||||
|
if len(rules) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
r := make([]*raw.ObjectAccessControl, 0, len(rules))
|
||||||
|
for _, rule := range rules {
|
||||||
|
r = append(r, rule.toRawObjectAccessControl("")) // bucket name unnecessary
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func toRawBucketACL(rules []ACLRule) []*raw.BucketAccessControl {
|
||||||
|
if len(rules) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
r := make([]*raw.BucketAccessControl, 0, len(rules))
|
||||||
|
for _, rule := range rules {
|
||||||
|
r = append(r, rule.toRawBucketAccessControl("")) // bucket name unnecessary
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ACLRule) toRawBucketAccessControl(bucket string) *raw.BucketAccessControl {
|
||||||
|
return &raw.BucketAccessControl{
|
||||||
|
Bucket: bucket,
|
||||||
|
Entity: string(r.Entity),
|
||||||
|
Role: string(r.Role),
|
||||||
|
// The other fields are not settable.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ACLRule) toRawObjectAccessControl(bucket string) *raw.ObjectAccessControl {
|
||||||
|
return &raw.ObjectAccessControl{
|
||||||
|
Bucket: bucket,
|
||||||
|
Entity: string(r.Entity),
|
||||||
|
Role: string(r.Role),
|
||||||
|
// The other fields are not settable.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toBucketProjectTeam(p *raw.BucketAccessControlProjectTeam) *ProjectTeam {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &ProjectTeam{
|
||||||
|
ProjectNumber: p.ProjectNumber,
|
||||||
|
Team: p.Team,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toObjectProjectTeam(p *raw.ObjectAccessControlProjectTeam) *ProjectTeam {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &ProjectTeam{
|
||||||
|
ProjectNumber: p.ProjectNumber,
|
||||||
|
Team: p.Team,
|
||||||
|
}
|
||||||
|
}
|
1195
vendor/cloud.google.com/go/storage/bucket.go
generated
vendored
Normal file
1195
vendor/cloud.google.com/go/storage/bucket.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
228
vendor/cloud.google.com/go/storage/copy.go
generated
vendored
Normal file
228
vendor/cloud.google.com/go/storage/copy.go
generated
vendored
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
// Copyright 2016 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"cloud.google.com/go/internal/trace"
|
||||||
|
raw "google.golang.org/api/storage/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CopierFrom creates a Copier that can copy src to dst.
|
||||||
|
// You can immediately call Run on the returned Copier, or
|
||||||
|
// you can configure it first.
|
||||||
|
//
|
||||||
|
// For Requester Pays buckets, the user project of dst is billed, unless it is empty,
|
||||||
|
// in which case the user project of src is billed.
|
||||||
|
func (dst *ObjectHandle) CopierFrom(src *ObjectHandle) *Copier {
|
||||||
|
return &Copier{dst: dst, src: src}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Copier copies a source object to a destination.
|
||||||
|
type Copier struct {
|
||||||
|
// ObjectAttrs are optional attributes to set on the destination object.
|
||||||
|
// Any attributes must be initialized before any calls on the Copier. Nil
|
||||||
|
// or zero-valued attributes are ignored.
|
||||||
|
ObjectAttrs
|
||||||
|
|
||||||
|
// RewriteToken can be set before calling Run to resume a copy
|
||||||
|
// operation. After Run returns a non-nil error, RewriteToken will
|
||||||
|
// have been updated to contain the value needed to resume the copy.
|
||||||
|
RewriteToken string
|
||||||
|
|
||||||
|
// ProgressFunc can be used to monitor the progress of a multi-RPC copy
|
||||||
|
// operation. If ProgressFunc is not nil and copying requires multiple
|
||||||
|
// calls to the underlying service (see
|
||||||
|
// https://cloud.google.com/storage/docs/json_api/v1/objects/rewrite), then
|
||||||
|
// ProgressFunc will be invoked after each call with the number of bytes of
|
||||||
|
// content copied so far and the total size in bytes of the source object.
|
||||||
|
//
|
||||||
|
// ProgressFunc is intended to make upload progress available to the
|
||||||
|
// application. For example, the implementation of ProgressFunc may update
|
||||||
|
// a progress bar in the application's UI, or log the result of
|
||||||
|
// float64(copiedBytes)/float64(totalBytes).
|
||||||
|
//
|
||||||
|
// ProgressFunc should return quickly without blocking.
|
||||||
|
ProgressFunc func(copiedBytes, totalBytes uint64)
|
||||||
|
|
||||||
|
// The Cloud KMS key, in the form projects/P/locations/L/keyRings/R/cryptoKeys/K,
|
||||||
|
// that will be used to encrypt the object. Overrides the object's KMSKeyName, if
|
||||||
|
// any.
|
||||||
|
//
|
||||||
|
// Providing both a DestinationKMSKeyName and a customer-supplied encryption key
|
||||||
|
// (via ObjectHandle.Key) on the destination object will result in an error when
|
||||||
|
// Run is called.
|
||||||
|
DestinationKMSKeyName string
|
||||||
|
|
||||||
|
dst, src *ObjectHandle
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run performs the copy.
|
||||||
|
func (c *Copier) Run(ctx context.Context) (attrs *ObjectAttrs, err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Copier.Run")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
if err := c.src.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := c.dst.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if c.DestinationKMSKeyName != "" && c.dst.encryptionKey != nil {
|
||||||
|
return nil, errors.New("storage: cannot use DestinationKMSKeyName with a customer-supplied encryption key")
|
||||||
|
}
|
||||||
|
// Convert destination attributes to raw form, omitting the bucket.
|
||||||
|
// If the bucket is included but name or content-type aren't, the service
|
||||||
|
// returns a 400 with "Required" as the only message. Omitting the bucket
|
||||||
|
// does not cause any problems.
|
||||||
|
rawObject := c.ObjectAttrs.toRawObject("")
|
||||||
|
for {
|
||||||
|
res, err := c.callRewrite(ctx, rawObject)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if c.ProgressFunc != nil {
|
||||||
|
c.ProgressFunc(uint64(res.TotalBytesRewritten), uint64(res.ObjectSize))
|
||||||
|
}
|
||||||
|
if res.Done { // Finished successfully.
|
||||||
|
return newObject(res.Resource), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Copier) callRewrite(ctx context.Context, rawObj *raw.Object) (*raw.RewriteResponse, error) {
|
||||||
|
call := c.dst.c.raw.Objects.Rewrite(c.src.bucket, c.src.object, c.dst.bucket, c.dst.object, rawObj)
|
||||||
|
|
||||||
|
call.Context(ctx).Projection("full")
|
||||||
|
if c.RewriteToken != "" {
|
||||||
|
call.RewriteToken(c.RewriteToken)
|
||||||
|
}
|
||||||
|
if c.DestinationKMSKeyName != "" {
|
||||||
|
call.DestinationKmsKeyName(c.DestinationKMSKeyName)
|
||||||
|
}
|
||||||
|
if c.PredefinedACL != "" {
|
||||||
|
call.DestinationPredefinedAcl(c.PredefinedACL)
|
||||||
|
}
|
||||||
|
if err := applyConds("Copy destination", c.dst.gen, c.dst.conds, call); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if c.dst.userProject != "" {
|
||||||
|
call.UserProject(c.dst.userProject)
|
||||||
|
} else if c.src.userProject != "" {
|
||||||
|
call.UserProject(c.src.userProject)
|
||||||
|
}
|
||||||
|
if err := applySourceConds(c.src.gen, c.src.conds, call); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := setEncryptionHeaders(call.Header(), c.dst.encryptionKey, false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := setEncryptionHeaders(call.Header(), c.src.encryptionKey, true); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var res *raw.RewriteResponse
|
||||||
|
var err error
|
||||||
|
setClientHeader(call.Header())
|
||||||
|
err = runWithRetry(ctx, func() error { res, err = call.Do(); return err })
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.RewriteToken = res.RewriteToken
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComposerFrom creates a Composer that can compose srcs into dst.
|
||||||
|
// You can immediately call Run on the returned Composer, or you can
|
||||||
|
// configure it first.
|
||||||
|
//
|
||||||
|
// The encryption key for the destination object will be used to decrypt all
|
||||||
|
// source objects and encrypt the destination object. It is an error
|
||||||
|
// to specify an encryption key for any of the source objects.
|
||||||
|
func (dst *ObjectHandle) ComposerFrom(srcs ...*ObjectHandle) *Composer {
|
||||||
|
return &Composer{dst: dst, srcs: srcs}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Composer composes source objects into a destination object.
|
||||||
|
//
|
||||||
|
// For Requester Pays buckets, the user project of dst is billed.
|
||||||
|
type Composer struct {
|
||||||
|
// ObjectAttrs are optional attributes to set on the destination object.
|
||||||
|
// Any attributes must be initialized before any calls on the Composer. Nil
|
||||||
|
// or zero-valued attributes are ignored.
|
||||||
|
ObjectAttrs
|
||||||
|
|
||||||
|
dst *ObjectHandle
|
||||||
|
srcs []*ObjectHandle
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run performs the compose operation.
|
||||||
|
func (c *Composer) Run(ctx context.Context) (attrs *ObjectAttrs, err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Composer.Run")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
if err := c.dst.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(c.srcs) == 0 {
|
||||||
|
return nil, errors.New("storage: at least one source object must be specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
req := &raw.ComposeRequest{}
|
||||||
|
// Compose requires a non-empty Destination, so we always set it,
|
||||||
|
// even if the caller-provided ObjectAttrs is the zero value.
|
||||||
|
req.Destination = c.ObjectAttrs.toRawObject(c.dst.bucket)
|
||||||
|
for _, src := range c.srcs {
|
||||||
|
if err := src.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if src.bucket != c.dst.bucket {
|
||||||
|
return nil, fmt.Errorf("storage: all source objects must be in bucket %q, found %q", c.dst.bucket, src.bucket)
|
||||||
|
}
|
||||||
|
if src.encryptionKey != nil {
|
||||||
|
return nil, fmt.Errorf("storage: compose source %s.%s must not have encryption key", src.bucket, src.object)
|
||||||
|
}
|
||||||
|
srcObj := &raw.ComposeRequestSourceObjects{
|
||||||
|
Name: src.object,
|
||||||
|
}
|
||||||
|
if err := applyConds("ComposeFrom source", src.gen, src.conds, composeSourceObj{srcObj}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.SourceObjects = append(req.SourceObjects, srcObj)
|
||||||
|
}
|
||||||
|
|
||||||
|
call := c.dst.c.raw.Objects.Compose(c.dst.bucket, c.dst.object, req).Context(ctx)
|
||||||
|
if err := applyConds("ComposeFrom destination", c.dst.gen, c.dst.conds, call); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if c.dst.userProject != "" {
|
||||||
|
call.UserProject(c.dst.userProject)
|
||||||
|
}
|
||||||
|
if c.PredefinedACL != "" {
|
||||||
|
call.DestinationPredefinedAcl(c.PredefinedACL)
|
||||||
|
}
|
||||||
|
if err := setEncryptionHeaders(call.Header(), c.dst.encryptionKey, false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var obj *raw.Object
|
||||||
|
setClientHeader(call.Header())
|
||||||
|
err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err })
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newObject(obj), nil
|
||||||
|
}
|
176
vendor/cloud.google.com/go/storage/doc.go
generated
vendored
Normal file
176
vendor/cloud.google.com/go/storage/doc.go
generated
vendored
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
// Copyright 2016 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package storage provides an easy way to work with Google Cloud Storage.
|
||||||
|
Google Cloud Storage stores data in named objects, which are grouped into buckets.
|
||||||
|
|
||||||
|
More information about Google Cloud Storage is available at
|
||||||
|
https://cloud.google.com/storage/docs.
|
||||||
|
|
||||||
|
See https://godoc.org/cloud.google.com/go for authentication, timeouts,
|
||||||
|
connection pooling and similar aspects of this package.
|
||||||
|
|
||||||
|
All of the methods of this package use exponential backoff to retry calls that fail
|
||||||
|
with certain errors, as described in
|
||||||
|
https://cloud.google.com/storage/docs/exponential-backoff. Retrying continues
|
||||||
|
indefinitely unless the controlling context is canceled or the client is closed. See
|
||||||
|
context.WithTimeout and context.WithCancel.
|
||||||
|
|
||||||
|
|
||||||
|
Creating a Client
|
||||||
|
|
||||||
|
To start working with this package, create a client:
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
client, err := storage.NewClient(ctx)
|
||||||
|
if err != nil {
|
||||||
|
// TODO: Handle error.
|
||||||
|
}
|
||||||
|
|
||||||
|
The client will use your default application credentials.
|
||||||
|
|
||||||
|
If you only wish to access public data, you can create
|
||||||
|
an unauthenticated client with
|
||||||
|
|
||||||
|
client, err := storage.NewClient(ctx, option.WithoutAuthentication())
|
||||||
|
|
||||||
|
Buckets
|
||||||
|
|
||||||
|
A Google Cloud Storage bucket is a collection of objects. To work with a
|
||||||
|
bucket, make a bucket handle:
|
||||||
|
|
||||||
|
bkt := client.Bucket(bucketName)
|
||||||
|
|
||||||
|
A handle is a reference to a bucket. You can have a handle even if the
|
||||||
|
bucket doesn't exist yet. To create a bucket in Google Cloud Storage,
|
||||||
|
call Create on the handle:
|
||||||
|
|
||||||
|
if err := bkt.Create(ctx, projectID, nil); err != nil {
|
||||||
|
// TODO: Handle error.
|
||||||
|
}
|
||||||
|
|
||||||
|
Note that although buckets are associated with projects, bucket names are
|
||||||
|
global across all projects.
|
||||||
|
|
||||||
|
Each bucket has associated metadata, represented in this package by
|
||||||
|
BucketAttrs. The third argument to BucketHandle.Create allows you to set
|
||||||
|
the initial BucketAttrs of a bucket. To retrieve a bucket's attributes, use
|
||||||
|
Attrs:
|
||||||
|
|
||||||
|
attrs, err := bkt.Attrs(ctx)
|
||||||
|
if err != nil {
|
||||||
|
// TODO: Handle error.
|
||||||
|
}
|
||||||
|
fmt.Printf("bucket %s, created at %s, is located in %s with storage class %s\n",
|
||||||
|
attrs.Name, attrs.Created, attrs.Location, attrs.StorageClass)
|
||||||
|
|
||||||
|
Objects
|
||||||
|
|
||||||
|
An object holds arbitrary data as a sequence of bytes, like a file. You
|
||||||
|
refer to objects using a handle, just as with buckets, but unlike buckets
|
||||||
|
you don't explicitly create an object. Instead, the first time you write
|
||||||
|
to an object it will be created. You can use the standard Go io.Reader
|
||||||
|
and io.Writer interfaces to read and write object data:
|
||||||
|
|
||||||
|
obj := bkt.Object("data")
|
||||||
|
// Write something to obj.
|
||||||
|
// w implements io.Writer.
|
||||||
|
w := obj.NewWriter(ctx)
|
||||||
|
// Write some text to obj. This will either create the object or overwrite whatever is there already.
|
||||||
|
if _, err := fmt.Fprintf(w, "This object contains text.\n"); err != nil {
|
||||||
|
// TODO: Handle error.
|
||||||
|
}
|
||||||
|
// Close, just like writing a file.
|
||||||
|
if err := w.Close(); err != nil {
|
||||||
|
// TODO: Handle error.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read it back.
|
||||||
|
r, err := obj.NewReader(ctx)
|
||||||
|
if err != nil {
|
||||||
|
// TODO: Handle error.
|
||||||
|
}
|
||||||
|
defer r.Close()
|
||||||
|
if _, err := io.Copy(os.Stdout, r); err != nil {
|
||||||
|
// TODO: Handle error.
|
||||||
|
}
|
||||||
|
// Prints "This object contains text."
|
||||||
|
|
||||||
|
Objects also have attributes, which you can fetch with Attrs:
|
||||||
|
|
||||||
|
objAttrs, err := obj.Attrs(ctx)
|
||||||
|
if err != nil {
|
||||||
|
// TODO: Handle error.
|
||||||
|
}
|
||||||
|
fmt.Printf("object %s has size %d and can be read using %s\n",
|
||||||
|
objAttrs.Name, objAttrs.Size, objAttrs.MediaLink)
|
||||||
|
|
||||||
|
ACLs
|
||||||
|
|
||||||
|
Both objects and buckets have ACLs (Access Control Lists). An ACL is a list of
|
||||||
|
ACLRules, each of which specifies the role of a user, group or project. ACLs
|
||||||
|
are suitable for fine-grained control, but you may prefer using IAM to control
|
||||||
|
access at the project level (see
|
||||||
|
https://cloud.google.com/storage/docs/access-control/iam).
|
||||||
|
|
||||||
|
To list the ACLs of a bucket or object, obtain an ACLHandle and call its List method:
|
||||||
|
|
||||||
|
acls, err := obj.ACL().List(ctx)
|
||||||
|
if err != nil {
|
||||||
|
// TODO: Handle error.
|
||||||
|
}
|
||||||
|
for _, rule := range acls {
|
||||||
|
fmt.Printf("%s has role %s\n", rule.Entity, rule.Role)
|
||||||
|
}
|
||||||
|
|
||||||
|
You can also set and delete ACLs.
|
||||||
|
|
||||||
|
Conditions
|
||||||
|
|
||||||
|
Every object has a generation and a metageneration. The generation changes
|
||||||
|
whenever the content changes, and the metageneration changes whenever the
|
||||||
|
metadata changes. Conditions let you check these values before an operation;
|
||||||
|
the operation only executes if the conditions match. You can use conditions to
|
||||||
|
prevent race conditions in read-modify-write operations.
|
||||||
|
|
||||||
|
For example, say you've read an object's metadata into objAttrs. Now
|
||||||
|
you want to write to that object, but only if its contents haven't changed
|
||||||
|
since you read it. Here is how to express that:
|
||||||
|
|
||||||
|
w = obj.If(storage.Conditions{GenerationMatch: objAttrs.Generation}).NewWriter(ctx)
|
||||||
|
// Proceed with writing as above.
|
||||||
|
|
||||||
|
Signed URLs
|
||||||
|
|
||||||
|
You can obtain a URL that lets anyone read or write an object for a limited time.
|
||||||
|
You don't need to create a client to do this. See the documentation of
|
||||||
|
SignedURL for details.
|
||||||
|
|
||||||
|
url, err := storage.SignedURL(bucketName, "shared-object", opts)
|
||||||
|
if err != nil {
|
||||||
|
// TODO: Handle error.
|
||||||
|
}
|
||||||
|
fmt.Println(url)
|
||||||
|
|
||||||
|
Errors
|
||||||
|
|
||||||
|
Errors returned by this client are often of the type [`googleapi.Error`](https://godoc.org/google.golang.org/api/googleapi#Error).
|
||||||
|
These errors can be introspected for more information by type asserting to the richer `googleapi.Error` type. For example:
|
||||||
|
|
||||||
|
if e, ok := err.(*googleapi.Error); ok {
|
||||||
|
if e.Code == 409 { ... }
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
package storage // import "cloud.google.com/go/storage"
|
32
vendor/cloud.google.com/go/storage/go110.go
generated
vendored
Normal file
32
vendor/cloud.google.com/go/storage/go110.go
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build go1.10
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import "google.golang.org/api/googleapi"
|
||||||
|
|
||||||
|
func shouldRetry(err error) bool {
|
||||||
|
switch e := err.(type) {
|
||||||
|
case *googleapi.Error:
|
||||||
|
// Retry on 429 and 5xx, according to
|
||||||
|
// https://cloud.google.com/storage/docs/exponential-backoff.
|
||||||
|
return e.Code == 429 || (e.Code >= 500 && e.Code < 600)
|
||||||
|
case interface{ Temporary() bool }:
|
||||||
|
return e.Temporary()
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
330
vendor/cloud.google.com/go/storage/hmac.go
generated
vendored
Normal file
330
vendor/cloud.google.com/go/storage/hmac.go
generated
vendored
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
// Copyright 2019 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"google.golang.org/api/iterator"
|
||||||
|
raw "google.golang.org/api/storage/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HMACState is the state of the HMAC key.
|
||||||
|
type HMACState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Active is the status for an active key that can be used to sign
|
||||||
|
// requests.
|
||||||
|
Active HMACState = "ACTIVE"
|
||||||
|
|
||||||
|
// Inactive is the status for an inactive key thus requests signed by
|
||||||
|
// this key will be denied.
|
||||||
|
Inactive HMACState = "INACTIVE"
|
||||||
|
|
||||||
|
// Deleted is the status for a key that is deleted.
|
||||||
|
// Once in this state the key cannot key cannot be recovered
|
||||||
|
// and does not count towards key limits. Deleted keys will be cleaned
|
||||||
|
// up later.
|
||||||
|
Deleted HMACState = "DELETED"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HMACKey is the representation of a Google Cloud Storage HMAC key.
|
||||||
|
//
|
||||||
|
// HMAC keys are used to authenticate signed access to objects. To enable HMAC key
|
||||||
|
// authentication, please visit https://cloud.google.com/storage/docs/migrating.
|
||||||
|
//
|
||||||
|
// This type is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
type HMACKey struct {
|
||||||
|
// The HMAC's secret key.
|
||||||
|
Secret string
|
||||||
|
|
||||||
|
// AccessID is the ID of the HMAC key.
|
||||||
|
AccessID string
|
||||||
|
|
||||||
|
// Etag is the HTTP/1.1 Entity tag.
|
||||||
|
Etag string
|
||||||
|
|
||||||
|
// ID is the ID of the HMAC key, including the ProjectID and AccessID.
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// ProjectID is the ID of the project that owns the
|
||||||
|
// service account to which the key authenticates.
|
||||||
|
ProjectID string
|
||||||
|
|
||||||
|
// ServiceAccountEmail is the email address
|
||||||
|
// of the key's associated service account.
|
||||||
|
ServiceAccountEmail string
|
||||||
|
|
||||||
|
// CreatedTime is the creation time of the HMAC key.
|
||||||
|
CreatedTime time.Time
|
||||||
|
|
||||||
|
// UpdatedTime is the last modification time of the HMAC key metadata.
|
||||||
|
UpdatedTime time.Time
|
||||||
|
|
||||||
|
// State is the state of the HMAC key.
|
||||||
|
// It can be one of StateActive, StateInactive or StateDeleted.
|
||||||
|
State HMACState
|
||||||
|
}
|
||||||
|
|
||||||
|
// HMACKeyHandle helps provide access and management for HMAC keys.
|
||||||
|
//
|
||||||
|
// This type is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
type HMACKeyHandle struct {
|
||||||
|
projectID string
|
||||||
|
accessID string
|
||||||
|
|
||||||
|
raw *raw.ProjectsHmacKeysService
|
||||||
|
}
|
||||||
|
|
||||||
|
// HMACKeyHandle creates a handle that will be used for HMACKey operations.
|
||||||
|
//
|
||||||
|
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
func (c *Client) HMACKeyHandle(projectID, accessID string) *HMACKeyHandle {
|
||||||
|
return &HMACKeyHandle{
|
||||||
|
projectID: projectID,
|
||||||
|
accessID: accessID,
|
||||||
|
raw: raw.NewProjectsHmacKeysService(c.raw),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get invokes an RPC to retrieve the HMAC key referenced by the
|
||||||
|
// HMACKeyHandle's accessID.
|
||||||
|
//
|
||||||
|
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
func (hkh *HMACKeyHandle) Get(ctx context.Context) (*HMACKey, error) {
|
||||||
|
call := hkh.raw.Get(hkh.projectID, hkh.accessID)
|
||||||
|
setClientHeader(call.Header())
|
||||||
|
|
||||||
|
var metadata *raw.HmacKeyMetadata
|
||||||
|
var err error
|
||||||
|
err = runWithRetry(ctx, func() error {
|
||||||
|
metadata, err = call.Context(ctx).Do()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
hkPb := &raw.HmacKey{
|
||||||
|
Metadata: metadata,
|
||||||
|
}
|
||||||
|
return pbHmacKeyToHMACKey(hkPb, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete invokes an RPC to delete the key referenced by accessID, on Google Cloud Storage.
|
||||||
|
// Only inactive HMAC keys can be deleted.
|
||||||
|
// After deletion, a key cannot be used to authenticate requests.
|
||||||
|
//
|
||||||
|
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
func (hkh *HMACKeyHandle) Delete(ctx context.Context) error {
|
||||||
|
delCall := hkh.raw.Delete(hkh.projectID, hkh.accessID)
|
||||||
|
setClientHeader(delCall.Header())
|
||||||
|
|
||||||
|
return runWithRetry(ctx, func() error {
|
||||||
|
return delCall.Context(ctx).Do()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func pbHmacKeyToHMACKey(pb *raw.HmacKey, updatedTimeCanBeNil bool) (*HMACKey, error) {
|
||||||
|
pbmd := pb.Metadata
|
||||||
|
if pbmd == nil {
|
||||||
|
return nil, errors.New("field Metadata cannot be nil")
|
||||||
|
}
|
||||||
|
createdTime, err := time.Parse(time.RFC3339, pbmd.TimeCreated)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("field CreatedTime: %v", err)
|
||||||
|
}
|
||||||
|
updatedTime, err := time.Parse(time.RFC3339, pbmd.Updated)
|
||||||
|
if err != nil && !updatedTimeCanBeNil {
|
||||||
|
return nil, fmt.Errorf("field UpdatedTime: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hmk := &HMACKey{
|
||||||
|
AccessID: pbmd.AccessId,
|
||||||
|
Secret: pb.Secret,
|
||||||
|
Etag: pbmd.Etag,
|
||||||
|
ID: pbmd.Id,
|
||||||
|
State: HMACState(pbmd.State),
|
||||||
|
ProjectID: pbmd.ProjectId,
|
||||||
|
CreatedTime: createdTime,
|
||||||
|
UpdatedTime: updatedTime,
|
||||||
|
|
||||||
|
ServiceAccountEmail: pbmd.ServiceAccountEmail,
|
||||||
|
}
|
||||||
|
|
||||||
|
return hmk, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateHMACKey invokes an RPC for Google Cloud Storage to create a new HMACKey.
|
||||||
|
//
|
||||||
|
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
func (c *Client) CreateHMACKey(ctx context.Context, projectID, serviceAccountEmail string) (*HMACKey, error) {
|
||||||
|
if projectID == "" {
|
||||||
|
return nil, errors.New("storage: expecting a non-blank projectID")
|
||||||
|
}
|
||||||
|
if serviceAccountEmail == "" {
|
||||||
|
return nil, errors.New("storage: expecting a non-blank service account email")
|
||||||
|
}
|
||||||
|
|
||||||
|
svc := raw.NewProjectsHmacKeysService(c.raw)
|
||||||
|
call := svc.Create(projectID, serviceAccountEmail)
|
||||||
|
setClientHeader(call.Header())
|
||||||
|
|
||||||
|
var hkPb *raw.HmacKey
|
||||||
|
var err error
|
||||||
|
err = runWithRetry(ctx, func() error {
|
||||||
|
hkPb, err = call.Context(ctx).Do()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pbHmacKeyToHMACKey(hkPb, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HMACKeyAttrsToUpdate defines the attributes of an HMACKey that will be updated.
|
||||||
|
//
|
||||||
|
// This type is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
type HMACKeyAttrsToUpdate struct {
|
||||||
|
// State is required and must be either StateActive or StateInactive.
|
||||||
|
State HMACState
|
||||||
|
|
||||||
|
// Etag is an optional field and it is the HTTP/1.1 Entity tag.
|
||||||
|
Etag string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update mutates the HMACKey referred to by accessID.
|
||||||
|
//
|
||||||
|
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
func (h *HMACKeyHandle) Update(ctx context.Context, au HMACKeyAttrsToUpdate) (*HMACKey, error) {
|
||||||
|
if au.State != Active && au.State != Inactive {
|
||||||
|
return nil, fmt.Errorf("storage: invalid state %q for update, must be either %q or %q", au.State, Active, Inactive)
|
||||||
|
}
|
||||||
|
|
||||||
|
call := h.raw.Update(h.projectID, h.accessID, &raw.HmacKeyMetadata{
|
||||||
|
Etag: au.Etag,
|
||||||
|
State: string(au.State),
|
||||||
|
})
|
||||||
|
setClientHeader(call.Header())
|
||||||
|
|
||||||
|
var metadata *raw.HmacKeyMetadata
|
||||||
|
var err error
|
||||||
|
err = runWithRetry(ctx, func() error {
|
||||||
|
metadata, err = call.Context(ctx).Do()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hkPb := &raw.HmacKey{
|
||||||
|
Metadata: metadata,
|
||||||
|
}
|
||||||
|
return pbHmacKeyToHMACKey(hkPb, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// An HMACKeysIterator is an iterator over HMACKeys.
|
||||||
|
//
|
||||||
|
// This type is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
type HMACKeysIterator struct {
|
||||||
|
ctx context.Context
|
||||||
|
raw *raw.ProjectsHmacKeysService
|
||||||
|
projectID string
|
||||||
|
hmacKeys []*HMACKey
|
||||||
|
pageInfo *iterator.PageInfo
|
||||||
|
nextFunc func() error
|
||||||
|
index int
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListHMACKeys returns an iterator for listing HMACKeys.
|
||||||
|
//
|
||||||
|
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
func (c *Client) ListHMACKeys(ctx context.Context, projectID string) *HMACKeysIterator {
|
||||||
|
it := &HMACKeysIterator{
|
||||||
|
ctx: ctx,
|
||||||
|
raw: raw.NewProjectsHmacKeysService(c.raw),
|
||||||
|
projectID: projectID,
|
||||||
|
}
|
||||||
|
|
||||||
|
it.pageInfo, it.nextFunc = iterator.NewPageInfo(
|
||||||
|
it.fetch,
|
||||||
|
func() int { return len(it.hmacKeys) - it.index },
|
||||||
|
func() interface{} {
|
||||||
|
prev := it.hmacKeys
|
||||||
|
it.hmacKeys = it.hmacKeys[:0]
|
||||||
|
it.index = 0
|
||||||
|
return prev
|
||||||
|
})
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next returns the next result. Its second return value is iterator.Done if
|
||||||
|
// there are no more results. Once Next returns iterator.Done, all subsequent
|
||||||
|
// calls will return iterator.Done.
|
||||||
|
//
|
||||||
|
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
func (it *HMACKeysIterator) Next() (*HMACKey, error) {
|
||||||
|
if err := it.nextFunc(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
key := it.hmacKeys[it.index]
|
||||||
|
it.index++
|
||||||
|
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||||
|
//
|
||||||
|
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
func (it *HMACKeysIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
|
||||||
|
|
||||||
|
func (it *HMACKeysIterator) fetch(pageSize int, pageToken string) (token string, err error) {
|
||||||
|
call := it.raw.List(it.projectID)
|
||||||
|
setClientHeader(call.Header())
|
||||||
|
call = call.PageToken(pageToken)
|
||||||
|
// By default we'll also show deleted keys and then
|
||||||
|
// let users filter on their own.
|
||||||
|
call = call.ShowDeletedKeys(true)
|
||||||
|
if pageSize > 0 {
|
||||||
|
call = call.MaxResults(int64(pageSize))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := it.ctx
|
||||||
|
var resp *raw.HmacKeysMetadata
|
||||||
|
err = runWithRetry(it.ctx, func() error {
|
||||||
|
resp, err = call.Context(ctx).Do()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, metadata := range resp.Items {
|
||||||
|
hkPb := &raw.HmacKey{
|
||||||
|
Metadata: metadata,
|
||||||
|
}
|
||||||
|
hkey, err := pbHmacKeyToHMACKey(hkPb, true)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
it.hmacKeys = append(it.hmacKeys, hkey)
|
||||||
|
}
|
||||||
|
return resp.NextPageToken, nil
|
||||||
|
}
|
130
vendor/cloud.google.com/go/storage/iam.go
generated
vendored
Normal file
130
vendor/cloud.google.com/go/storage/iam.go
generated
vendored
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"cloud.google.com/go/iam"
|
||||||
|
"cloud.google.com/go/internal/trace"
|
||||||
|
raw "google.golang.org/api/storage/v1"
|
||||||
|
iampb "google.golang.org/genproto/googleapis/iam/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IAM provides access to IAM access control for the bucket.
|
||||||
|
func (b *BucketHandle) IAM() *iam.Handle {
|
||||||
|
return iam.InternalNewHandleClient(&iamClient{
|
||||||
|
raw: b.c.raw,
|
||||||
|
userProject: b.userProject,
|
||||||
|
}, b.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// iamClient implements the iam.client interface.
|
||||||
|
type iamClient struct {
|
||||||
|
raw *raw.Service
|
||||||
|
userProject string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *iamClient) Get(ctx context.Context, resource string) (p *iampb.Policy, err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Get")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
call := c.raw.Buckets.GetIamPolicy(resource)
|
||||||
|
setClientHeader(call.Header())
|
||||||
|
if c.userProject != "" {
|
||||||
|
call.UserProject(c.userProject)
|
||||||
|
}
|
||||||
|
var rp *raw.Policy
|
||||||
|
err = runWithRetry(ctx, func() error {
|
||||||
|
rp, err = call.Context(ctx).Do()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return iamFromStoragePolicy(rp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *iamClient) Set(ctx context.Context, resource string, p *iampb.Policy) (err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Set")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
rp := iamToStoragePolicy(p)
|
||||||
|
call := c.raw.Buckets.SetIamPolicy(resource, rp)
|
||||||
|
setClientHeader(call.Header())
|
||||||
|
if c.userProject != "" {
|
||||||
|
call.UserProject(c.userProject)
|
||||||
|
}
|
||||||
|
return runWithRetry(ctx, func() error {
|
||||||
|
_, err := call.Context(ctx).Do()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *iamClient) Test(ctx context.Context, resource string, perms []string) (permissions []string, err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Test")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
call := c.raw.Buckets.TestIamPermissions(resource, perms)
|
||||||
|
setClientHeader(call.Header())
|
||||||
|
if c.userProject != "" {
|
||||||
|
call.UserProject(c.userProject)
|
||||||
|
}
|
||||||
|
var res *raw.TestIamPermissionsResponse
|
||||||
|
err = runWithRetry(ctx, func() error {
|
||||||
|
res, err = call.Context(ctx).Do()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res.Permissions, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamToStoragePolicy(ip *iampb.Policy) *raw.Policy {
|
||||||
|
return &raw.Policy{
|
||||||
|
Bindings: iamToStorageBindings(ip.Bindings),
|
||||||
|
Etag: string(ip.Etag),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamToStorageBindings(ibs []*iampb.Binding) []*raw.PolicyBindings {
|
||||||
|
var rbs []*raw.PolicyBindings
|
||||||
|
for _, ib := range ibs {
|
||||||
|
rbs = append(rbs, &raw.PolicyBindings{
|
||||||
|
Role: ib.Role,
|
||||||
|
Members: ib.Members,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return rbs
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamFromStoragePolicy(rp *raw.Policy) *iampb.Policy {
|
||||||
|
return &iampb.Policy{
|
||||||
|
Bindings: iamFromStorageBindings(rp.Bindings),
|
||||||
|
Etag: []byte(rp.Etag),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamFromStorageBindings(rbs []*raw.PolicyBindings) []*iampb.Binding {
|
||||||
|
var ibs []*iampb.Binding
|
||||||
|
for _, rb := range rbs {
|
||||||
|
ibs = append(ibs, &iampb.Binding{
|
||||||
|
Role: rb.Role,
|
||||||
|
Members: rb.Members,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return ibs
|
||||||
|
}
|
37
vendor/cloud.google.com/go/storage/invoke.go
generated
vendored
Normal file
37
vendor/cloud.google.com/go/storage/invoke.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2014 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"cloud.google.com/go/internal"
|
||||||
|
gax "github.com/googleapis/gax-go/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// runWithRetry calls the function until it returns nil or a non-retryable error, or
|
||||||
|
// the context is done.
|
||||||
|
func runWithRetry(ctx context.Context, call func() error) error {
|
||||||
|
return internal.Retry(ctx, gax.Backoff{}, func() (stop bool, err error) {
|
||||||
|
err = call()
|
||||||
|
if err == nil {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if shouldRetry(err) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, err
|
||||||
|
})
|
||||||
|
}
|
42
vendor/cloud.google.com/go/storage/not_go110.go
generated
vendored
Normal file
42
vendor/cloud.google.com/go/storage/not_go110.go
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build !go1.10
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"google.golang.org/api/googleapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
func shouldRetry(err error) bool {
|
||||||
|
switch e := err.(type) {
|
||||||
|
case *googleapi.Error:
|
||||||
|
// Retry on 429 and 5xx, according to
|
||||||
|
// https://cloud.google.com/storage/docs/exponential-backoff.
|
||||||
|
return e.Code == 429 || (e.Code >= 500 && e.Code < 600)
|
||||||
|
case *url.Error:
|
||||||
|
// Retry on REFUSED_STREAM.
|
||||||
|
// Unfortunately the error type is unexported, so we resort to string
|
||||||
|
// matching.
|
||||||
|
return strings.Contains(e.Error(), "REFUSED_STREAM")
|
||||||
|
case interface{ Temporary() bool }:
|
||||||
|
return e.Temporary()
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
188
vendor/cloud.google.com/go/storage/notifications.go
generated
vendored
Normal file
188
vendor/cloud.google.com/go/storage/notifications.go
generated
vendored
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"cloud.google.com/go/internal/trace"
|
||||||
|
raw "google.golang.org/api/storage/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Notification describes how to send Cloud PubSub messages when certain
|
||||||
|
// events occur in a bucket.
|
||||||
|
type Notification struct {
|
||||||
|
//The ID of the notification.
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// The ID of the topic to which this subscription publishes.
|
||||||
|
TopicID string
|
||||||
|
|
||||||
|
// The ID of the project to which the topic belongs.
|
||||||
|
TopicProjectID string
|
||||||
|
|
||||||
|
// Only send notifications about listed event types. If empty, send notifications
|
||||||
|
// for all event types.
|
||||||
|
// See https://cloud.google.com/storage/docs/pubsub-notifications#events.
|
||||||
|
EventTypes []string
|
||||||
|
|
||||||
|
// If present, only apply this notification configuration to object names that
|
||||||
|
// begin with this prefix.
|
||||||
|
ObjectNamePrefix string
|
||||||
|
|
||||||
|
// An optional list of additional attributes to attach to each Cloud PubSub
|
||||||
|
// message published for this notification subscription.
|
||||||
|
CustomAttributes map[string]string
|
||||||
|
|
||||||
|
// The contents of the message payload.
|
||||||
|
// See https://cloud.google.com/storage/docs/pubsub-notifications#payload.
|
||||||
|
PayloadFormat string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Values for Notification.PayloadFormat.
|
||||||
|
const (
|
||||||
|
// Send no payload with notification messages.
|
||||||
|
NoPayload = "NONE"
|
||||||
|
|
||||||
|
// Send object metadata as JSON with notification messages.
|
||||||
|
JSONPayload = "JSON_API_V1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Values for Notification.EventTypes.
|
||||||
|
const (
|
||||||
|
// Event that occurs when an object is successfully created.
|
||||||
|
ObjectFinalizeEvent = "OBJECT_FINALIZE"
|
||||||
|
|
||||||
|
// Event that occurs when the metadata of an existing object changes.
|
||||||
|
ObjectMetadataUpdateEvent = "OBJECT_METADATA_UPDATE"
|
||||||
|
|
||||||
|
// Event that occurs when an object is permanently deleted.
|
||||||
|
ObjectDeleteEvent = "OBJECT_DELETE"
|
||||||
|
|
||||||
|
// Event that occurs when the live version of an object becomes an
|
||||||
|
// archived version.
|
||||||
|
ObjectArchiveEvent = "OBJECT_ARCHIVE"
|
||||||
|
)
|
||||||
|
|
||||||
|
func toNotification(rn *raw.Notification) *Notification {
|
||||||
|
n := &Notification{
|
||||||
|
ID: rn.Id,
|
||||||
|
EventTypes: rn.EventTypes,
|
||||||
|
ObjectNamePrefix: rn.ObjectNamePrefix,
|
||||||
|
CustomAttributes: rn.CustomAttributes,
|
||||||
|
PayloadFormat: rn.PayloadFormat,
|
||||||
|
}
|
||||||
|
n.TopicProjectID, n.TopicID = parseNotificationTopic(rn.Topic)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
var topicRE = regexp.MustCompile("^//pubsub.googleapis.com/projects/([^/]+)/topics/([^/]+)")
|
||||||
|
|
||||||
|
// parseNotificationTopic extracts the project and topic IDs from from the full
|
||||||
|
// resource name returned by the service. If the name is malformed, it returns
|
||||||
|
// "?" for both IDs.
|
||||||
|
func parseNotificationTopic(nt string) (projectID, topicID string) {
|
||||||
|
matches := topicRE.FindStringSubmatch(nt)
|
||||||
|
if matches == nil {
|
||||||
|
return "?", "?"
|
||||||
|
}
|
||||||
|
return matches[1], matches[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
func toRawNotification(n *Notification) *raw.Notification {
|
||||||
|
return &raw.Notification{
|
||||||
|
Id: n.ID,
|
||||||
|
Topic: fmt.Sprintf("//pubsub.googleapis.com/projects/%s/topics/%s",
|
||||||
|
n.TopicProjectID, n.TopicID),
|
||||||
|
EventTypes: n.EventTypes,
|
||||||
|
ObjectNamePrefix: n.ObjectNamePrefix,
|
||||||
|
CustomAttributes: n.CustomAttributes,
|
||||||
|
PayloadFormat: string(n.PayloadFormat),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddNotification adds a notification to b. You must set n's TopicProjectID, TopicID
|
||||||
|
// and PayloadFormat, and must not set its ID. The other fields are all optional. The
|
||||||
|
// returned Notification's ID can be used to refer to it.
|
||||||
|
func (b *BucketHandle) AddNotification(ctx context.Context, n *Notification) (ret *Notification, err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.AddNotification")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
if n.ID != "" {
|
||||||
|
return nil, errors.New("storage: AddNotification: ID must not be set")
|
||||||
|
}
|
||||||
|
if n.TopicProjectID == "" {
|
||||||
|
return nil, errors.New("storage: AddNotification: missing TopicProjectID")
|
||||||
|
}
|
||||||
|
if n.TopicID == "" {
|
||||||
|
return nil, errors.New("storage: AddNotification: missing TopicID")
|
||||||
|
}
|
||||||
|
call := b.c.raw.Notifications.Insert(b.name, toRawNotification(n))
|
||||||
|
setClientHeader(call.Header())
|
||||||
|
if b.userProject != "" {
|
||||||
|
call.UserProject(b.userProject)
|
||||||
|
}
|
||||||
|
rn, err := call.Context(ctx).Do()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return toNotification(rn), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notifications returns all the Notifications configured for this bucket, as a map
|
||||||
|
// indexed by notification ID.
|
||||||
|
func (b *BucketHandle) Notifications(ctx context.Context) (n map[string]*Notification, err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Notifications")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
call := b.c.raw.Notifications.List(b.name)
|
||||||
|
setClientHeader(call.Header())
|
||||||
|
if b.userProject != "" {
|
||||||
|
call.UserProject(b.userProject)
|
||||||
|
}
|
||||||
|
var res *raw.Notifications
|
||||||
|
err = runWithRetry(ctx, func() error {
|
||||||
|
res, err = call.Context(ctx).Do()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return notificationsToMap(res.Items), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func notificationsToMap(rns []*raw.Notification) map[string]*Notification {
|
||||||
|
m := map[string]*Notification{}
|
||||||
|
for _, rn := range rns {
|
||||||
|
m[rn.Id] = toNotification(rn)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteNotification deletes the notification with the given ID.
|
||||||
|
func (b *BucketHandle) DeleteNotification(ctx context.Context, id string) (err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.DeleteNotification")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
call := b.c.raw.Notifications.Delete(b.name, id)
|
||||||
|
setClientHeader(call.Header())
|
||||||
|
if b.userProject != "" {
|
||||||
|
call.UserProject(b.userProject)
|
||||||
|
}
|
||||||
|
return call.Context(ctx).Do()
|
||||||
|
}
|
403
vendor/cloud.google.com/go/storage/reader.go
generated
vendored
Normal file
403
vendor/cloud.google.com/go/storage/reader.go
generated
vendored
Normal file
@ -0,0 +1,403 @@
|
|||||||
|
// Copyright 2016 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"hash/crc32"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cloud.google.com/go/internal/trace"
|
||||||
|
"google.golang.org/api/googleapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
var crc32cTable = crc32.MakeTable(crc32.Castagnoli)
|
||||||
|
|
||||||
|
// ReaderObjectAttrs are attributes about the object being read. These are populated
|
||||||
|
// during the New call. This struct only holds a subset of object attributes: to
|
||||||
|
// get the full set of attributes, use ObjectHandle.Attrs.
|
||||||
|
//
|
||||||
|
// Each field is read-only.
|
||||||
|
type ReaderObjectAttrs struct {
|
||||||
|
// Size is the length of the object's content.
|
||||||
|
Size int64
|
||||||
|
|
||||||
|
// StartOffset is the byte offset within the object
|
||||||
|
// from which reading begins.
|
||||||
|
// This value is only non-zero for range requests.
|
||||||
|
StartOffset int64
|
||||||
|
|
||||||
|
// ContentType is the MIME type of the object's content.
|
||||||
|
ContentType string
|
||||||
|
|
||||||
|
// ContentEncoding is the encoding of the object's content.
|
||||||
|
ContentEncoding string
|
||||||
|
|
||||||
|
// CacheControl specifies whether and for how long browser and Internet
|
||||||
|
// caches are allowed to cache your objects.
|
||||||
|
CacheControl string
|
||||||
|
|
||||||
|
// LastModified is the time that the object was last modified.
|
||||||
|
LastModified time.Time
|
||||||
|
|
||||||
|
// Generation is the generation number of the object's content.
|
||||||
|
Generation int64
|
||||||
|
|
||||||
|
// Metageneration is the version of the metadata for this object at
|
||||||
|
// this generation. This field is used for preconditions and for
|
||||||
|
// detecting changes in metadata. A metageneration number is only
|
||||||
|
// meaningful in the context of a particular generation of a
|
||||||
|
// particular object.
|
||||||
|
Metageneration int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewReader creates a new Reader to read the contents of the
|
||||||
|
// object.
|
||||||
|
// ErrObjectNotExist will be returned if the object is not found.
|
||||||
|
//
|
||||||
|
// The caller must call Close on the returned Reader when done reading.
|
||||||
|
func (o *ObjectHandle) NewReader(ctx context.Context) (*Reader, error) {
|
||||||
|
return o.NewRangeReader(ctx, 0, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRangeReader reads part of an object, reading at most length bytes
|
||||||
|
// starting at the given offset. If length is negative, the object is read
|
||||||
|
// until the end. If offset is negative, the object is read abs(offset) bytes
|
||||||
|
// from the end, and length must also be negative to indicate all remaining
|
||||||
|
// bytes will be read.
|
||||||
|
func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64) (r *Reader, err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.NewRangeReader")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
if err := o.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if offset < 0 && length >= 0 {
|
||||||
|
return nil, fmt.Errorf("storage: invalid offset %d < 0 requires negative length", offset)
|
||||||
|
}
|
||||||
|
if o.conds != nil {
|
||||||
|
if err := o.conds.validate("NewRangeReader"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u := &url.URL{
|
||||||
|
Scheme: o.c.scheme,
|
||||||
|
Host: o.c.readHost,
|
||||||
|
Path: fmt.Sprintf("/%s/%s", o.bucket, o.object),
|
||||||
|
}
|
||||||
|
verb := "GET"
|
||||||
|
if length == 0 {
|
||||||
|
verb = "HEAD"
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest(verb, u.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req = req.WithContext(ctx)
|
||||||
|
if o.userProject != "" {
|
||||||
|
req.Header.Set("X-Goog-User-Project", o.userProject)
|
||||||
|
}
|
||||||
|
if o.readCompressed {
|
||||||
|
req.Header.Set("Accept-Encoding", "gzip")
|
||||||
|
}
|
||||||
|
if err := setEncryptionHeaders(req.Header, o.encryptionKey, false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gen := o.gen
|
||||||
|
|
||||||
|
// Define a function that initiates a Read with offset and length, assuming we
|
||||||
|
// have already read seen bytes.
|
||||||
|
reopen := func(seen int64) (*http.Response, error) {
|
||||||
|
start := offset + seen
|
||||||
|
if length < 0 && start < 0 {
|
||||||
|
req.Header.Set("Range", fmt.Sprintf("bytes=%d", start))
|
||||||
|
} else if length < 0 && start > 0 {
|
||||||
|
req.Header.Set("Range", fmt.Sprintf("bytes=%d-", start))
|
||||||
|
} else if length > 0 {
|
||||||
|
// The end character isn't affected by how many bytes we've seen.
|
||||||
|
req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", start, offset+length-1))
|
||||||
|
}
|
||||||
|
// We wait to assign conditions here because the generation number can change in between reopen() runs.
|
||||||
|
req.URL.RawQuery = conditionsQuery(gen, o.conds)
|
||||||
|
var res *http.Response
|
||||||
|
err = runWithRetry(ctx, func() error {
|
||||||
|
res, err = o.c.hc.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if res.StatusCode == http.StatusNotFound {
|
||||||
|
res.Body.Close()
|
||||||
|
return ErrObjectNotExist
|
||||||
|
}
|
||||||
|
if res.StatusCode < 200 || res.StatusCode > 299 {
|
||||||
|
body, _ := ioutil.ReadAll(res.Body)
|
||||||
|
res.Body.Close()
|
||||||
|
return &googleapi.Error{
|
||||||
|
Code: res.StatusCode,
|
||||||
|
Header: res.Header,
|
||||||
|
Body: string(body),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if start > 0 && length != 0 && res.StatusCode != http.StatusPartialContent {
|
||||||
|
res.Body.Close()
|
||||||
|
return errors.New("storage: partial request not satisfied")
|
||||||
|
}
|
||||||
|
// If a generation hasn't been specified, and this is the first response we get, let's record the
|
||||||
|
// generation. In future requests we'll use this generation as a precondition to avoid data races.
|
||||||
|
if gen < 0 && res.Header.Get("X-Goog-Generation") != "" {
|
||||||
|
gen64, err := strconv.ParseInt(res.Header.Get("X-Goog-Generation"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
gen = gen64
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := reopen(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
size int64 // total size of object, even if a range was requested.
|
||||||
|
checkCRC bool
|
||||||
|
crc uint32
|
||||||
|
startOffset int64 // non-zero if range request.
|
||||||
|
)
|
||||||
|
if res.StatusCode == http.StatusPartialContent {
|
||||||
|
cr := strings.TrimSpace(res.Header.Get("Content-Range"))
|
||||||
|
if !strings.HasPrefix(cr, "bytes ") || !strings.Contains(cr, "/") {
|
||||||
|
return nil, fmt.Errorf("storage: invalid Content-Range %q", cr)
|
||||||
|
}
|
||||||
|
size, err = strconv.ParseInt(cr[strings.LastIndex(cr, "/")+1:], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("storage: invalid Content-Range %q", cr)
|
||||||
|
}
|
||||||
|
|
||||||
|
dashIndex := strings.Index(cr, "-")
|
||||||
|
if dashIndex >= 0 {
|
||||||
|
startOffset, err = strconv.ParseInt(cr[len("bytes="):dashIndex], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("storage: invalid Content-Range %q: %v", cr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size = res.ContentLength
|
||||||
|
// Check the CRC iff all of the following hold:
|
||||||
|
// - We asked for content (length != 0).
|
||||||
|
// - We got all the content (status != PartialContent).
|
||||||
|
// - The server sent a CRC header.
|
||||||
|
// - The Go http stack did not uncompress the file.
|
||||||
|
// - We were not served compressed data that was uncompressed on download.
|
||||||
|
// The problem with the last two cases is that the CRC will not match -- GCS
|
||||||
|
// computes it on the compressed contents, but we compute it on the
|
||||||
|
// uncompressed contents.
|
||||||
|
if length != 0 && !res.Uncompressed && !uncompressedByServer(res) {
|
||||||
|
crc, checkCRC = parseCRC32c(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
remain := res.ContentLength
|
||||||
|
body := res.Body
|
||||||
|
if length == 0 {
|
||||||
|
remain = 0
|
||||||
|
body.Close()
|
||||||
|
body = emptyBody
|
||||||
|
}
|
||||||
|
var metaGen int64
|
||||||
|
if res.Header.Get("X-Goog-Generation") != "" {
|
||||||
|
metaGen, err = strconv.ParseInt(res.Header.Get("X-Goog-Metageneration"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var lm time.Time
|
||||||
|
if res.Header.Get("Last-Modified") != "" {
|
||||||
|
lm, err = http.ParseTime(res.Header.Get("Last-Modified"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs := ReaderObjectAttrs{
|
||||||
|
Size: size,
|
||||||
|
ContentType: res.Header.Get("Content-Type"),
|
||||||
|
ContentEncoding: res.Header.Get("Content-Encoding"),
|
||||||
|
CacheControl: res.Header.Get("Cache-Control"),
|
||||||
|
LastModified: lm,
|
||||||
|
StartOffset: startOffset,
|
||||||
|
Generation: gen,
|
||||||
|
Metageneration: metaGen,
|
||||||
|
}
|
||||||
|
return &Reader{
|
||||||
|
Attrs: attrs,
|
||||||
|
body: body,
|
||||||
|
size: size,
|
||||||
|
remain: remain,
|
||||||
|
wantCRC: crc,
|
||||||
|
checkCRC: checkCRC,
|
||||||
|
reopen: reopen,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func uncompressedByServer(res *http.Response) bool {
|
||||||
|
// If the data is stored as gzip but is not encoded as gzip, then it
|
||||||
|
// was uncompressed by the server.
|
||||||
|
return res.Header.Get("X-Goog-Stored-Content-Encoding") == "gzip" &&
|
||||||
|
res.Header.Get("Content-Encoding") != "gzip"
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCRC32c(res *http.Response) (uint32, bool) {
|
||||||
|
const prefix = "crc32c="
|
||||||
|
for _, spec := range res.Header["X-Goog-Hash"] {
|
||||||
|
if strings.HasPrefix(spec, prefix) {
|
||||||
|
c, err := decodeUint32(spec[len(prefix):])
|
||||||
|
if err == nil {
|
||||||
|
return c, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
var emptyBody = ioutil.NopCloser(strings.NewReader(""))
|
||||||
|
|
||||||
|
// Reader reads a Cloud Storage object.
|
||||||
|
// It implements io.Reader.
|
||||||
|
//
|
||||||
|
// Typically, a Reader computes the CRC of the downloaded content and compares it to
|
||||||
|
// the stored CRC, returning an error from Read if there is a mismatch. This integrity check
|
||||||
|
// is skipped if transcoding occurs. See https://cloud.google.com/storage/docs/transcoding.
|
||||||
|
type Reader struct {
|
||||||
|
Attrs ReaderObjectAttrs
|
||||||
|
body io.ReadCloser
|
||||||
|
seen, remain, size int64
|
||||||
|
checkCRC bool // should we check the CRC?
|
||||||
|
wantCRC uint32 // the CRC32c value the server sent in the header
|
||||||
|
gotCRC uint32 // running crc
|
||||||
|
reopen func(seen int64) (*http.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the Reader. It must be called when done reading.
|
||||||
|
func (r *Reader) Close() error {
|
||||||
|
return r.body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reader) Read(p []byte) (int, error) {
|
||||||
|
n, err := r.readWithRetry(p)
|
||||||
|
if r.remain != -1 {
|
||||||
|
r.remain -= int64(n)
|
||||||
|
}
|
||||||
|
if r.checkCRC {
|
||||||
|
r.gotCRC = crc32.Update(r.gotCRC, crc32cTable, p[:n])
|
||||||
|
// Check CRC here. It would be natural to check it in Close, but
|
||||||
|
// everybody defers Close on the assumption that it doesn't return
|
||||||
|
// anything worth looking at.
|
||||||
|
if err == io.EOF {
|
||||||
|
if r.gotCRC != r.wantCRC {
|
||||||
|
return n, fmt.Errorf("storage: bad CRC on read: got %d, want %d",
|
||||||
|
r.gotCRC, r.wantCRC)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reader) readWithRetry(p []byte) (int, error) {
|
||||||
|
n := 0
|
||||||
|
for len(p[n:]) > 0 {
|
||||||
|
m, err := r.body.Read(p[n:])
|
||||||
|
n += m
|
||||||
|
r.seen += int64(m)
|
||||||
|
if !shouldRetryRead(err) {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
// Read failed, but we will try again. Send a ranged read request that takes
|
||||||
|
// into account the number of bytes we've already seen.
|
||||||
|
res, err := r.reopen(r.seen)
|
||||||
|
if err != nil {
|
||||||
|
// reopen already retries
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
r.body.Close()
|
||||||
|
r.body = res.Body
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldRetryRead(err error) bool {
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return strings.HasSuffix(err.Error(), "INTERNAL_ERROR") && strings.Contains(reflect.TypeOf(err).String(), "http2")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the size of the object in bytes.
|
||||||
|
// The returned value is always the same and is not affected by
|
||||||
|
// calls to Read or Close.
|
||||||
|
//
|
||||||
|
// Deprecated: use Reader.Attrs.Size.
|
||||||
|
func (r *Reader) Size() int64 {
|
||||||
|
return r.Attrs.Size
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remain returns the number of bytes left to read, or -1 if unknown.
|
||||||
|
func (r *Reader) Remain() int64 {
|
||||||
|
return r.remain
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContentType returns the content type of the object.
|
||||||
|
//
|
||||||
|
// Deprecated: use Reader.Attrs.ContentType.
|
||||||
|
func (r *Reader) ContentType() string {
|
||||||
|
return r.Attrs.ContentType
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContentEncoding returns the content encoding of the object.
|
||||||
|
//
|
||||||
|
// Deprecated: use Reader.Attrs.ContentEncoding.
|
||||||
|
func (r *Reader) ContentEncoding() string {
|
||||||
|
return r.Attrs.ContentEncoding
|
||||||
|
}
|
||||||
|
|
||||||
|
// CacheControl returns the cache control of the object.
|
||||||
|
//
|
||||||
|
// Deprecated: use Reader.Attrs.CacheControl.
|
||||||
|
func (r *Reader) CacheControl() string {
|
||||||
|
return r.Attrs.CacheControl
|
||||||
|
}
|
||||||
|
|
||||||
|
// LastModified returns the value of the Last-Modified header.
|
||||||
|
//
|
||||||
|
// Deprecated: use Reader.Attrs.LastModified.
|
||||||
|
func (r *Reader) LastModified() (time.Time, error) {
|
||||||
|
return r.Attrs.LastModified, nil
|
||||||
|
}
|
1369
vendor/cloud.google.com/go/storage/storage.go
generated
vendored
Normal file
1369
vendor/cloud.google.com/go/storage/storage.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
30067
vendor/cloud.google.com/go/storage/storage.replay
generated
vendored
Normal file
30067
vendor/cloud.google.com/go/storage/storage.replay
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
260
vendor/cloud.google.com/go/storage/writer.go
generated
vendored
Normal file
260
vendor/cloud.google.com/go/storage/writer.go
generated
vendored
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
// Copyright 2014 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"google.golang.org/api/googleapi"
|
||||||
|
raw "google.golang.org/api/storage/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Writer writes a Cloud Storage object.
|
||||||
|
type Writer struct {
|
||||||
|
// ObjectAttrs are optional attributes to set on the object. Any attributes
|
||||||
|
// must be initialized before the first Write call. Nil or zero-valued
|
||||||
|
// attributes are ignored.
|
||||||
|
ObjectAttrs
|
||||||
|
|
||||||
|
// SendCRC specifies whether to transmit a CRC32C field. It should be set
|
||||||
|
// to true in addition to setting the Writer's CRC32C field, because zero
|
||||||
|
// is a valid CRC and normally a zero would not be transmitted.
|
||||||
|
// If a CRC32C is sent, and the data written does not match the checksum,
|
||||||
|
// the write will be rejected.
|
||||||
|
SendCRC32C bool
|
||||||
|
|
||||||
|
// ChunkSize controls the maximum number of bytes of the object that the
|
||||||
|
// Writer will attempt to send to the server in a single request. Objects
|
||||||
|
// smaller than the size will be sent in a single request, while larger
|
||||||
|
// objects will be split over multiple requests. The size will be rounded up
|
||||||
|
// to the nearest multiple of 256K. If zero, chunking will be disabled and
|
||||||
|
// the object will be uploaded in a single request.
|
||||||
|
//
|
||||||
|
// ChunkSize will default to a reasonable value. If you perform many concurrent
|
||||||
|
// writes of small objects, you may wish set ChunkSize to a value that matches
|
||||||
|
// your objects' sizes to avoid consuming large amounts of memory.
|
||||||
|
//
|
||||||
|
// ChunkSize must be set before the first Write call.
|
||||||
|
ChunkSize int
|
||||||
|
|
||||||
|
// ProgressFunc can be used to monitor the progress of a large write.
|
||||||
|
// operation. If ProgressFunc is not nil and writing requires multiple
|
||||||
|
// calls to the underlying service (see
|
||||||
|
// https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload),
|
||||||
|
// then ProgressFunc will be invoked after each call with the number of bytes of
|
||||||
|
// content copied so far.
|
||||||
|
//
|
||||||
|
// ProgressFunc should return quickly without blocking.
|
||||||
|
ProgressFunc func(int64)
|
||||||
|
|
||||||
|
ctx context.Context
|
||||||
|
o *ObjectHandle
|
||||||
|
|
||||||
|
opened bool
|
||||||
|
pw *io.PipeWriter
|
||||||
|
|
||||||
|
donec chan struct{} // closed after err and obj are set.
|
||||||
|
obj *ObjectAttrs
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Writer) open() error {
|
||||||
|
attrs := w.ObjectAttrs
|
||||||
|
// Check the developer didn't change the object Name (this is unfortunate, but
|
||||||
|
// we don't want to store an object under the wrong name).
|
||||||
|
if attrs.Name != w.o.object {
|
||||||
|
return fmt.Errorf("storage: Writer.Name %q does not match object name %q", attrs.Name, w.o.object)
|
||||||
|
}
|
||||||
|
if !utf8.ValidString(attrs.Name) {
|
||||||
|
return fmt.Errorf("storage: object name %q is not valid UTF-8", attrs.Name)
|
||||||
|
}
|
||||||
|
if attrs.KMSKeyName != "" && w.o.encryptionKey != nil {
|
||||||
|
return errors.New("storage: cannot use KMSKeyName with a customer-supplied encryption key")
|
||||||
|
}
|
||||||
|
pr, pw := io.Pipe()
|
||||||
|
w.pw = pw
|
||||||
|
w.opened = true
|
||||||
|
|
||||||
|
go w.monitorCancel()
|
||||||
|
|
||||||
|
if w.ChunkSize < 0 {
|
||||||
|
return errors.New("storage: Writer.ChunkSize must be non-negative")
|
||||||
|
}
|
||||||
|
mediaOpts := []googleapi.MediaOption{
|
||||||
|
googleapi.ChunkSize(w.ChunkSize),
|
||||||
|
}
|
||||||
|
if c := attrs.ContentType; c != "" {
|
||||||
|
mediaOpts = append(mediaOpts, googleapi.ContentType(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer close(w.donec)
|
||||||
|
|
||||||
|
rawObj := attrs.toRawObject(w.o.bucket)
|
||||||
|
if w.SendCRC32C {
|
||||||
|
rawObj.Crc32c = encodeUint32(attrs.CRC32C)
|
||||||
|
}
|
||||||
|
if w.MD5 != nil {
|
||||||
|
rawObj.Md5Hash = base64.StdEncoding.EncodeToString(w.MD5)
|
||||||
|
}
|
||||||
|
if w.o.c.envHost != "" {
|
||||||
|
w.o.c.raw.BasePath = fmt.Sprintf("%s://%s", w.o.c.scheme, w.o.c.envHost)
|
||||||
|
}
|
||||||
|
call := w.o.c.raw.Objects.Insert(w.o.bucket, rawObj).
|
||||||
|
Media(pr, mediaOpts...).
|
||||||
|
Projection("full").
|
||||||
|
Context(w.ctx)
|
||||||
|
|
||||||
|
if w.ProgressFunc != nil {
|
||||||
|
call.ProgressUpdater(func(n, _ int64) { w.ProgressFunc(n) })
|
||||||
|
}
|
||||||
|
if attrs.KMSKeyName != "" {
|
||||||
|
call.KmsKeyName(attrs.KMSKeyName)
|
||||||
|
}
|
||||||
|
if attrs.PredefinedACL != "" {
|
||||||
|
call.PredefinedAcl(attrs.PredefinedACL)
|
||||||
|
}
|
||||||
|
if err := setEncryptionHeaders(call.Header(), w.o.encryptionKey, false); err != nil {
|
||||||
|
w.mu.Lock()
|
||||||
|
w.err = err
|
||||||
|
w.mu.Unlock()
|
||||||
|
pr.CloseWithError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var resp *raw.Object
|
||||||
|
err := applyConds("NewWriter", w.o.gen, w.o.conds, call)
|
||||||
|
if err == nil {
|
||||||
|
if w.o.userProject != "" {
|
||||||
|
call.UserProject(w.o.userProject)
|
||||||
|
}
|
||||||
|
setClientHeader(call.Header())
|
||||||
|
|
||||||
|
// The internals that perform call.Do automatically retry
|
||||||
|
// uploading chunks, hence no need to add retries here.
|
||||||
|
// See issue https://github.com/googleapis/google-cloud-go/issues/1507.
|
||||||
|
//
|
||||||
|
// However, since this whole call's internals involve making the initial
|
||||||
|
// resumable upload session, the first HTTP request is not retried.
|
||||||
|
// TODO: Follow-up with google.golang.org/gensupport to solve
|
||||||
|
// https://github.com/googleapis/google-api-go-client/issues/392.
|
||||||
|
resp, err = call.Do()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
w.mu.Lock()
|
||||||
|
w.err = err
|
||||||
|
w.mu.Unlock()
|
||||||
|
pr.CloseWithError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.obj = newObject(resp)
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write appends to w. It implements the io.Writer interface.
|
||||||
|
//
|
||||||
|
// Since writes happen asynchronously, Write may return a nil
|
||||||
|
// error even though the write failed (or will fail). Always
|
||||||
|
// use the error returned from Writer.Close to determine if
|
||||||
|
// the upload was successful.
|
||||||
|
func (w *Writer) Write(p []byte) (n int, err error) {
|
||||||
|
w.mu.Lock()
|
||||||
|
werr := w.err
|
||||||
|
w.mu.Unlock()
|
||||||
|
if werr != nil {
|
||||||
|
return 0, werr
|
||||||
|
}
|
||||||
|
if !w.opened {
|
||||||
|
if err := w.open(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n, err = w.pw.Write(p)
|
||||||
|
if err != nil {
|
||||||
|
w.mu.Lock()
|
||||||
|
werr := w.err
|
||||||
|
w.mu.Unlock()
|
||||||
|
// Preserve existing functionality that when context is canceled, Write will return
|
||||||
|
// context.Canceled instead of "io: read/write on closed pipe". This hides the
|
||||||
|
// pipe implementation detail from users and makes Write seem as though it's an RPC.
|
||||||
|
if werr == context.Canceled || werr == context.DeadlineExceeded {
|
||||||
|
return n, werr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close completes the write operation and flushes any buffered data.
|
||||||
|
// If Close doesn't return an error, metadata about the written object
|
||||||
|
// can be retrieved by calling Attrs.
|
||||||
|
func (w *Writer) Close() error {
|
||||||
|
if !w.opened {
|
||||||
|
if err := w.open(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closing either the read or write causes the entire pipe to close.
|
||||||
|
if err := w.pw.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
<-w.donec
|
||||||
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
|
return w.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// monitorCancel is intended to be used as a background goroutine. It monitors the
|
||||||
|
// context, and when it observes that the context has been canceled, it manually
|
||||||
|
// closes things that do not take a context.
|
||||||
|
func (w *Writer) monitorCancel() {
|
||||||
|
select {
|
||||||
|
case <-w.ctx.Done():
|
||||||
|
w.mu.Lock()
|
||||||
|
werr := w.ctx.Err()
|
||||||
|
w.err = werr
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
// Closing either the read or write causes the entire pipe to close.
|
||||||
|
w.CloseWithError(werr)
|
||||||
|
case <-w.donec:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseWithError aborts the write operation with the provided error.
|
||||||
|
// CloseWithError always returns nil.
|
||||||
|
//
|
||||||
|
// Deprecated: cancel the context passed to NewWriter instead.
|
||||||
|
func (w *Writer) CloseWithError(err error) error {
|
||||||
|
if !w.opened {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return w.pw.CloseWithError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attrs returns metadata about a successfully-written object.
|
||||||
|
// It's only valid to call it after Close returns nil.
|
||||||
|
func (w *Writer) Attrs() *ObjectAttrs {
|
||||||
|
return w.obj
|
||||||
|
}
|
18
vendor/code.gitea.io/sdk/gitea/oauth2.go
generated
vendored
18
vendor/code.gitea.io/sdk/gitea/oauth2.go
generated
vendored
@ -13,13 +13,12 @@ import (
|
|||||||
|
|
||||||
// Oauth2 represents an Oauth2 Application
|
// Oauth2 represents an Oauth2 Application
|
||||||
type Oauth2 struct {
|
type Oauth2 struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
ClientID string `json:"client_id"`
|
ClientID string `json:"client_id"`
|
||||||
ClientSecret string `json:"client_secret"`
|
ClientSecret string `json:"client_secret"`
|
||||||
RedirectURIs []string `json:"redirect_uris"`
|
RedirectURIs []string `json:"redirect_uris"`
|
||||||
ConfidentialClient bool `json:"confidential_client"`
|
Created time.Time `json:"created"`
|
||||||
Created time.Time `json:"created"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListOauth2Option for listing Oauth2 Applications
|
// ListOauth2Option for listing Oauth2 Applications
|
||||||
@ -29,9 +28,8 @@ type ListOauth2Option struct {
|
|||||||
|
|
||||||
// CreateOauth2Option required options for creating an Application
|
// CreateOauth2Option required options for creating an Application
|
||||||
type CreateOauth2Option struct {
|
type CreateOauth2Option struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
ConfidentialClient bool `json:"confidential_client"`
|
RedirectURIs []string `json:"redirect_uris"`
|
||||||
RedirectURIs []string `json:"redirect_uris"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateOauth2 create an Oauth2 Application and returns a completed Oauth2 object.
|
// CreateOauth2 create an Oauth2 Application and returns a completed Oauth2 object.
|
||||||
|
25
vendor/github.com/Masterminds/goutils/cryptorandomstringutils.go
generated
vendored
25
vendor/github.com/Masterminds/goutils/cryptorandomstringutils.go
generated
vendored
@ -21,6 +21,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"regexp"
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -98,7 +99,27 @@ Returns:
|
|||||||
error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...)
|
error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...)
|
||||||
*/
|
*/
|
||||||
func CryptoRandomAlphaNumeric(count int) (string, error) {
|
func CryptoRandomAlphaNumeric(count int) (string, error) {
|
||||||
return CryptoRandom(count, 0, 0, true, true)
|
if count == 0 {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
RandomString, err := CryptoRandom(count, 0, 0, true, true)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Error: %s", err)
|
||||||
|
}
|
||||||
|
match, err := regexp.MatchString("([0-9]+)", RandomString)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !match {
|
||||||
|
//Get the position between 0 and the length of the string-1 to insert a random number
|
||||||
|
position := getCryptoRandomInt(count)
|
||||||
|
//Insert a random number between [0-9] in the position
|
||||||
|
RandomString = RandomString[:position] + string('0' + getCryptoRandomInt(10)) + RandomString[position + 1:]
|
||||||
|
return RandomString, err
|
||||||
|
}
|
||||||
|
return RandomString, err
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -183,7 +204,7 @@ func CryptoRandom(count int, start int, end int, letters bool, numbers bool, cha
|
|||||||
if chars == nil {
|
if chars == nil {
|
||||||
ch = rune(getCryptoRandomInt(gap) + int64(start))
|
ch = rune(getCryptoRandomInt(gap) + int64(start))
|
||||||
} else {
|
} else {
|
||||||
ch = chars[getCryptoRandomInt(gap)+int64(start)]
|
ch = chars[getCryptoRandomInt(gap) + int64(start)]
|
||||||
}
|
}
|
||||||
|
|
||||||
if letters && unicode.IsLetter(ch) || numbers && unicode.IsDigit(ch) || !letters && !numbers {
|
if letters && unicode.IsLetter(ch) || numbers && unicode.IsDigit(ch) || !letters && !numbers {
|
||||||
|
24
vendor/github.com/Masterminds/goutils/randomstringutils.go
generated
vendored
24
vendor/github.com/Masterminds/goutils/randomstringutils.go
generated
vendored
@ -20,6 +20,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
@ -74,10 +75,12 @@ func RandomNumeric(count int) (string, error) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
RandomAlphabetic creates a random string whose length is the number of characters specified.
|
RandomAlphabetic creates a random string whose length is the number of characters specified.
|
||||||
Characters will be chosen from the set of alphabetic characters.
|
Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
count - the length of random string to create
|
count - the length of random string to create
|
||||||
|
letters - if true, generated string may include alphabetic characters
|
||||||
|
numbers - if true, generated string may include numeric characters
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
string - the random string
|
string - the random string
|
||||||
@ -99,7 +102,24 @@ Returns:
|
|||||||
error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
|
error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
|
||||||
*/
|
*/
|
||||||
func RandomAlphaNumeric(count int) (string, error) {
|
func RandomAlphaNumeric(count int) (string, error) {
|
||||||
return Random(count, 0, 0, true, true)
|
RandomString, err := Random(count, 0, 0, true, true)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Error: %s", err)
|
||||||
|
}
|
||||||
|
match, err := regexp.MatchString("([0-9]+)", RandomString)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !match {
|
||||||
|
//Get the position between 0 and the length of the string-1 to insert a random number
|
||||||
|
position := rand.Intn(count)
|
||||||
|
//Insert a random number between [0-9] in the position
|
||||||
|
RandomString = RandomString[:position] + string('0'+rand.Intn(10)) + RandomString[position+1:]
|
||||||
|
return RandomString, err
|
||||||
|
}
|
||||||
|
return RandomString, err
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
16
vendor/github.com/Masterminds/goutils/stringutils.go
generated
vendored
16
vendor/github.com/Masterminds/goutils/stringutils.go
generated
vendored
@ -222,19 +222,3 @@ func IndexOf(str string, sub string, start int) int {
|
|||||||
func IsEmpty(str string) bool {
|
func IsEmpty(str string) bool {
|
||||||
return len(str) == 0
|
return len(str) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns either the passed in string, or if the string is empty, the value of defaultStr.
|
|
||||||
func DefaultString(str string, defaultStr string) string {
|
|
||||||
if IsEmpty(str) {
|
|
||||||
return defaultStr
|
|
||||||
}
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns either the passed in string, or if the string is whitespace, empty (""), the value of defaultStr.
|
|
||||||
func DefaultIfBlank(str string, defaultStr string) string {
|
|
||||||
if IsBlank(str) {
|
|
||||||
return defaultStr
|
|
||||||
}
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
29
vendor/github.com/Masterminds/semver/.travis.yml
generated
vendored
Normal file
29
vendor/github.com/Masterminds/semver/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.6.x
|
||||||
|
- 1.7.x
|
||||||
|
- 1.8.x
|
||||||
|
- 1.9.x
|
||||||
|
- 1.10.x
|
||||||
|
- 1.11.x
|
||||||
|
- 1.12.x
|
||||||
|
- tip
|
||||||
|
|
||||||
|
# Setting sudo access to false will let Travis CI use containers rather than
|
||||||
|
# VMs to run the tests. For more details see:
|
||||||
|
# - http://docs.travis-ci.com/user/workers/container-based-infrastructure/
|
||||||
|
# - http://docs.travis-ci.com/user/workers/standard-infrastructure/
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
script:
|
||||||
|
- make setup
|
||||||
|
- make test
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
webhooks:
|
||||||
|
urls:
|
||||||
|
- https://webhooks.gitter.im/e/06e3328629952dabe3e0
|
||||||
|
on_success: change # options: [always|never|change] default: always
|
||||||
|
on_failure: always # options: [always|never|change] default: always
|
||||||
|
on_start: never # options: [always|never|change] default: always
|
109
vendor/github.com/Masterminds/semver/CHANGELOG.md
generated
vendored
Normal file
109
vendor/github.com/Masterminds/semver/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
# 1.5.0 (2019-09-11)
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- #103: Add basic fuzzing for `NewVersion()` (thanks @jesse-c)
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- #82: Clarify wildcard meaning in range constraints and update tests for it (thanks @greysteil)
|
||||||
|
- #83: Clarify caret operator range for pre-1.0.0 dependencies (thanks @greysteil)
|
||||||
|
- #72: Adding docs comment pointing to vert for a cli
|
||||||
|
- #71: Update the docs on pre-release comparator handling
|
||||||
|
- #89: Test with new go versions (thanks @thedevsaddam)
|
||||||
|
- #87: Added $ to ValidPrerelease for better validation (thanks @jeremycarroll)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- #78: Fix unchecked error in example code (thanks @ravron)
|
||||||
|
- #70: Fix the handling of pre-releases and the 0.0.0 release edge case
|
||||||
|
- #97: Fixed copyright file for proper display on GitHub
|
||||||
|
- #107: Fix handling prerelease when sorting alphanum and num
|
||||||
|
- #109: Fixed where Validate sometimes returns wrong message on error
|
||||||
|
|
||||||
|
# 1.4.2 (2018-04-10)
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
- #72: Updated the docs to point to vert for a console appliaction
|
||||||
|
- #71: Update the docs on pre-release comparator handling
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- #70: Fix the handling of pre-releases and the 0.0.0 release edge case
|
||||||
|
|
||||||
|
# 1.4.1 (2018-04-02)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- Fixed #64: Fix pre-release precedence issue (thanks @uudashr)
|
||||||
|
|
||||||
|
# 1.4.0 (2017-10-04)
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
- #61: Update NewVersion to parse ints with a 64bit int size (thanks @zknill)
|
||||||
|
|
||||||
|
# 1.3.1 (2017-07-10)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- Fixed #57: number comparisons in prerelease sometimes inaccurate
|
||||||
|
|
||||||
|
# 1.3.0 (2017-05-02)
|
||||||
|
|
||||||
|
## Added
|
||||||
|
- #45: Added json (un)marshaling support (thanks @mh-cbon)
|
||||||
|
- Stability marker. See https://masterminds.github.io/stability/
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- #51: Fix handling of single digit tilde constraint (thanks @dgodd)
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
- #55: The godoc icon moved from png to svg
|
||||||
|
|
||||||
|
# 1.2.3 (2017-04-03)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- #46: Fixed 0.x.x and 0.0.x in constraints being treated as *
|
||||||
|
|
||||||
|
# Release 1.2.2 (2016-12-13)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- #34: Fixed issue where hyphen range was not working with pre-release parsing.
|
||||||
|
|
||||||
|
# Release 1.2.1 (2016-11-28)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- #24: Fixed edge case issue where constraint "> 0" does not handle "0.0.1-alpha"
|
||||||
|
properly.
|
||||||
|
|
||||||
|
# Release 1.2.0 (2016-11-04)
|
||||||
|
|
||||||
|
## Added
|
||||||
|
- #20: Added MustParse function for versions (thanks @adamreese)
|
||||||
|
- #15: Added increment methods on versions (thanks @mh-cbon)
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
- Issue #21: Per the SemVer spec (section 9) a pre-release is unstable and
|
||||||
|
might not satisfy the intended compatibility. The change here ignores pre-releases
|
||||||
|
on constraint checks (e.g., ~ or ^) when a pre-release is not part of the
|
||||||
|
constraint. For example, `^1.2.3` will ignore pre-releases while
|
||||||
|
`^1.2.3-alpha` will include them.
|
||||||
|
|
||||||
|
# Release 1.1.1 (2016-06-30)
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
- Issue #9: Speed up version comparison performance (thanks @sdboyer)
|
||||||
|
- Issue #8: Added benchmarks (thanks @sdboyer)
|
||||||
|
- Updated Go Report Card URL to new location
|
||||||
|
- Updated Readme to add code snippet formatting (thanks @mh-cbon)
|
||||||
|
- Updating tagging to v[SemVer] structure for compatibility with other tools.
|
||||||
|
|
||||||
|
# Release 1.1.0 (2016-03-11)
|
||||||
|
|
||||||
|
- Issue #2: Implemented validation to provide reasons a versions failed a
|
||||||
|
constraint.
|
||||||
|
|
||||||
|
# Release 1.0.1 (2015-12-31)
|
||||||
|
|
||||||
|
- Fixed #1: * constraint failing on valid versions.
|
||||||
|
|
||||||
|
# Release 1.0.0 (2015-10-20)
|
||||||
|
|
||||||
|
- Initial release
|
36
vendor/github.com/Masterminds/semver/Makefile
generated
vendored
Normal file
36
vendor/github.com/Masterminds/semver/Makefile
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
.PHONY: setup
|
||||||
|
setup:
|
||||||
|
go get -u gopkg.in/alecthomas/gometalinter.v1
|
||||||
|
gometalinter.v1 --install
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test: validate lint
|
||||||
|
@echo "==> Running tests"
|
||||||
|
go test -v
|
||||||
|
|
||||||
|
.PHONY: validate
|
||||||
|
validate:
|
||||||
|
@echo "==> Running static validations"
|
||||||
|
@gometalinter.v1 \
|
||||||
|
--disable-all \
|
||||||
|
--enable deadcode \
|
||||||
|
--severity deadcode:error \
|
||||||
|
--enable gofmt \
|
||||||
|
--enable gosimple \
|
||||||
|
--enable ineffassign \
|
||||||
|
--enable misspell \
|
||||||
|
--enable vet \
|
||||||
|
--tests \
|
||||||
|
--vendor \
|
||||||
|
--deadline 60s \
|
||||||
|
./... || exit_code=1
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
lint:
|
||||||
|
@echo "==> Running linters"
|
||||||
|
@gometalinter.v1 \
|
||||||
|
--disable-all \
|
||||||
|
--enable golint \
|
||||||
|
--vendor \
|
||||||
|
--deadline 60s \
|
||||||
|
./... || :
|
194
vendor/github.com/Masterminds/semver/README.md
generated
vendored
Normal file
194
vendor/github.com/Masterminds/semver/README.md
generated
vendored
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
# SemVer
|
||||||
|
|
||||||
|
The `semver` package provides the ability to work with [Semantic Versions](http://semver.org) in Go. Specifically it provides the ability to:
|
||||||
|
|
||||||
|
* Parse semantic versions
|
||||||
|
* Sort semantic versions
|
||||||
|
* Check if a semantic version fits within a set of constraints
|
||||||
|
* Optionally work with a `v` prefix
|
||||||
|
|
||||||
|
[![Stability:
|
||||||
|
Active](https://masterminds.github.io/stability/active.svg)](https://masterminds.github.io/stability/active.html)
|
||||||
|
[![Build Status](https://travis-ci.org/Masterminds/semver.svg)](https://travis-ci.org/Masterminds/semver) [![Build status](https://ci.appveyor.com/api/projects/status/jfk66lib7hb985k8/branch/master?svg=true&passingText=windows%20build%20passing&failingText=windows%20build%20failing)](https://ci.appveyor.com/project/mattfarina/semver/branch/master) [![GoDoc](https://godoc.org/github.com/Masterminds/semver?status.svg)](https://godoc.org/github.com/Masterminds/semver) [![Go Report Card](https://goreportcard.com/badge/github.com/Masterminds/semver)](https://goreportcard.com/report/github.com/Masterminds/semver)
|
||||||
|
|
||||||
|
If you are looking for a command line tool for version comparisons please see
|
||||||
|
[vert](https://github.com/Masterminds/vert) which uses this library.
|
||||||
|
|
||||||
|
## Parsing Semantic Versions
|
||||||
|
|
||||||
|
To parse a semantic version use the `NewVersion` function. For example,
|
||||||
|
|
||||||
|
```go
|
||||||
|
v, err := semver.NewVersion("1.2.3-beta.1+build345")
|
||||||
|
```
|
||||||
|
|
||||||
|
If there is an error the version wasn't parseable. The version object has methods
|
||||||
|
to get the parts of the version, compare it to other versions, convert the
|
||||||
|
version back into a string, and get the original string. For more details
|
||||||
|
please see the [documentation](https://godoc.org/github.com/Masterminds/semver).
|
||||||
|
|
||||||
|
## Sorting Semantic Versions
|
||||||
|
|
||||||
|
A set of versions can be sorted using the [`sort`](https://golang.org/pkg/sort/)
|
||||||
|
package from the standard library. For example,
|
||||||
|
|
||||||
|
```go
|
||||||
|
raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",}
|
||||||
|
vs := make([]*semver.Version, len(raw))
|
||||||
|
for i, r := range raw {
|
||||||
|
v, err := semver.NewVersion(r)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error parsing version: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vs[i] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(semver.Collection(vs))
|
||||||
|
```
|
||||||
|
|
||||||
|
## Checking Version Constraints
|
||||||
|
|
||||||
|
Checking a version against version constraints is one of the most featureful
|
||||||
|
parts of the package.
|
||||||
|
|
||||||
|
```go
|
||||||
|
c, err := semver.NewConstraint(">= 1.2.3")
|
||||||
|
if err != nil {
|
||||||
|
// Handle constraint not being parseable.
|
||||||
|
}
|
||||||
|
|
||||||
|
v, _ := semver.NewVersion("1.3")
|
||||||
|
if err != nil {
|
||||||
|
// Handle version not being parseable.
|
||||||
|
}
|
||||||
|
// Check if the version meets the constraints. The a variable will be true.
|
||||||
|
a := c.Check(v)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Basic Comparisons
|
||||||
|
|
||||||
|
There are two elements to the comparisons. First, a comparison string is a list
|
||||||
|
of comma separated and comparisons. These are then separated by || separated or
|
||||||
|
comparisons. For example, `">= 1.2, < 3.0.0 || >= 4.2.3"` is looking for a
|
||||||
|
comparison that's greater than or equal to 1.2 and less than 3.0.0 or is
|
||||||
|
greater than or equal to 4.2.3.
|
||||||
|
|
||||||
|
The basic comparisons are:
|
||||||
|
|
||||||
|
* `=`: equal (aliased to no operator)
|
||||||
|
* `!=`: not equal
|
||||||
|
* `>`: greater than
|
||||||
|
* `<`: less than
|
||||||
|
* `>=`: greater than or equal to
|
||||||
|
* `<=`: less than or equal to
|
||||||
|
|
||||||
|
## Working With Pre-release Versions
|
||||||
|
|
||||||
|
Pre-releases, for those not familiar with them, are used for software releases
|
||||||
|
prior to stable or generally available releases. Examples of pre-releases include
|
||||||
|
development, alpha, beta, and release candidate releases. A pre-release may be
|
||||||
|
a version such as `1.2.3-beta.1` while the stable release would be `1.2.3`. In the
|
||||||
|
order of precidence, pre-releases come before their associated releases. In this
|
||||||
|
example `1.2.3-beta.1 < 1.2.3`.
|
||||||
|
|
||||||
|
According to the Semantic Version specification pre-releases may not be
|
||||||
|
API compliant with their release counterpart. It says,
|
||||||
|
|
||||||
|
> A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version.
|
||||||
|
|
||||||
|
SemVer comparisons without a pre-release comparator will skip pre-release versions.
|
||||||
|
For example, `>=1.2.3` will skip pre-releases when looking at a list of releases
|
||||||
|
while `>=1.2.3-0` will evaluate and find pre-releases.
|
||||||
|
|
||||||
|
The reason for the `0` as a pre-release version in the example comparison is
|
||||||
|
because pre-releases can only contain ASCII alphanumerics and hyphens (along with
|
||||||
|
`.` separators), per the spec. Sorting happens in ASCII sort order, again per the spec. The lowest character is a `0` in ASCII sort order (see an [ASCII Table](http://www.asciitable.com/))
|
||||||
|
|
||||||
|
Understanding ASCII sort ordering is important because A-Z comes before a-z. That
|
||||||
|
means `>=1.2.3-BETA` will return `1.2.3-alpha`. What you might expect from case
|
||||||
|
sensitivity doesn't apply here. This is due to ASCII sort ordering which is what
|
||||||
|
the spec specifies.
|
||||||
|
|
||||||
|
## Hyphen Range Comparisons
|
||||||
|
|
||||||
|
There are multiple methods to handle ranges and the first is hyphens ranges.
|
||||||
|
These look like:
|
||||||
|
|
||||||
|
* `1.2 - 1.4.5` which is equivalent to `>= 1.2, <= 1.4.5`
|
||||||
|
* `2.3.4 - 4.5` which is equivalent to `>= 2.3.4, <= 4.5`
|
||||||
|
|
||||||
|
## Wildcards In Comparisons
|
||||||
|
|
||||||
|
The `x`, `X`, and `*` characters can be used as a wildcard character. This works
|
||||||
|
for all comparison operators. When used on the `=` operator it falls
|
||||||
|
back to the pack level comparison (see tilde below). For example,
|
||||||
|
|
||||||
|
* `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
||||||
|
* `>= 1.2.x` is equivalent to `>= 1.2.0`
|
||||||
|
* `<= 2.x` is equivalent to `< 3`
|
||||||
|
* `*` is equivalent to `>= 0.0.0`
|
||||||
|
|
||||||
|
## Tilde Range Comparisons (Patch)
|
||||||
|
|
||||||
|
The tilde (`~`) comparison operator is for patch level ranges when a minor
|
||||||
|
version is specified and major level changes when the minor number is missing.
|
||||||
|
For example,
|
||||||
|
|
||||||
|
* `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0`
|
||||||
|
* `~1` is equivalent to `>= 1, < 2`
|
||||||
|
* `~2.3` is equivalent to `>= 2.3, < 2.4`
|
||||||
|
* `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
||||||
|
* `~1.x` is equivalent to `>= 1, < 2`
|
||||||
|
|
||||||
|
## Caret Range Comparisons (Major)
|
||||||
|
|
||||||
|
The caret (`^`) comparison operator is for major level changes. This is useful
|
||||||
|
when comparisons of API versions as a major change is API breaking. For example,
|
||||||
|
|
||||||
|
* `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0`
|
||||||
|
* `^0.0.1` is equivalent to `>= 0.0.1, < 1.0.0`
|
||||||
|
* `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0`
|
||||||
|
* `^2.3` is equivalent to `>= 2.3, < 3`
|
||||||
|
* `^2.x` is equivalent to `>= 2.0.0, < 3`
|
||||||
|
|
||||||
|
# Validation
|
||||||
|
|
||||||
|
In addition to testing a version against a constraint, a version can be validated
|
||||||
|
against a constraint. When validation fails a slice of errors containing why a
|
||||||
|
version didn't meet the constraint is returned. For example,
|
||||||
|
|
||||||
|
```go
|
||||||
|
c, err := semver.NewConstraint("<= 1.2.3, >= 1.4")
|
||||||
|
if err != nil {
|
||||||
|
// Handle constraint not being parseable.
|
||||||
|
}
|
||||||
|
|
||||||
|
v, _ := semver.NewVersion("1.3")
|
||||||
|
if err != nil {
|
||||||
|
// Handle version not being parseable.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate a version against a constraint.
|
||||||
|
a, msgs := c.Validate(v)
|
||||||
|
// a is false
|
||||||
|
for _, m := range msgs {
|
||||||
|
fmt.Println(m)
|
||||||
|
|
||||||
|
// Loops over the errors which would read
|
||||||
|
// "1.3 is greater than 1.2.3"
|
||||||
|
// "1.3 is less than 1.4"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Fuzzing
|
||||||
|
|
||||||
|
[dvyukov/go-fuzz](https://github.com/dvyukov/go-fuzz) is used for fuzzing.
|
||||||
|
|
||||||
|
1. `go-fuzz-build`
|
||||||
|
2. `go-fuzz -workdir=fuzz`
|
||||||
|
|
||||||
|
# Contribute
|
||||||
|
|
||||||
|
If you find an issue or want to contribute please file an [issue](https://github.com/Masterminds/semver/issues)
|
||||||
|
or [create a pull request](https://github.com/Masterminds/semver/pulls).
|
44
vendor/github.com/Masterminds/semver/appveyor.yml
generated
vendored
Normal file
44
vendor/github.com/Masterminds/semver/appveyor.yml
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
version: build-{build}.{branch}
|
||||||
|
|
||||||
|
clone_folder: C:\gopath\src\github.com\Masterminds\semver
|
||||||
|
shallow_clone: true
|
||||||
|
|
||||||
|
environment:
|
||||||
|
GOPATH: C:\gopath
|
||||||
|
|
||||||
|
platform:
|
||||||
|
- x64
|
||||||
|
|
||||||
|
install:
|
||||||
|
- go version
|
||||||
|
- go env
|
||||||
|
- go get -u gopkg.in/alecthomas/gometalinter.v1
|
||||||
|
- set PATH=%PATH%;%GOPATH%\bin
|
||||||
|
- gometalinter.v1.exe --install
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
- go install -v ./...
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
- "gometalinter.v1 \
|
||||||
|
--disable-all \
|
||||||
|
--enable deadcode \
|
||||||
|
--severity deadcode:error \
|
||||||
|
--enable gofmt \
|
||||||
|
--enable gosimple \
|
||||||
|
--enable ineffassign \
|
||||||
|
--enable misspell \
|
||||||
|
--enable vet \
|
||||||
|
--tests \
|
||||||
|
--vendor \
|
||||||
|
--deadline 60s \
|
||||||
|
./... || exit_code=1"
|
||||||
|
- "gometalinter.v1 \
|
||||||
|
--disable-all \
|
||||||
|
--enable golint \
|
||||||
|
--vendor \
|
||||||
|
--deadline 60s \
|
||||||
|
./... || :"
|
||||||
|
- go test -v
|
||||||
|
|
||||||
|
deploy: off
|
423
vendor/github.com/Masterminds/semver/constraints.go
generated
vendored
Normal file
423
vendor/github.com/Masterminds/semver/constraints.go
generated
vendored
Normal file
@ -0,0 +1,423 @@
|
|||||||
|
package semver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Constraints is one or more constraint that a semantic version can be
|
||||||
|
// checked against.
|
||||||
|
type Constraints struct {
|
||||||
|
constraints [][]*constraint
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConstraint returns a Constraints instance that a Version instance can
|
||||||
|
// be checked against. If there is a parse error it will be returned.
|
||||||
|
func NewConstraint(c string) (*Constraints, error) {
|
||||||
|
|
||||||
|
// Rewrite - ranges into a comparison operation.
|
||||||
|
c = rewriteRange(c)
|
||||||
|
|
||||||
|
ors := strings.Split(c, "||")
|
||||||
|
or := make([][]*constraint, len(ors))
|
||||||
|
for k, v := range ors {
|
||||||
|
cs := strings.Split(v, ",")
|
||||||
|
result := make([]*constraint, len(cs))
|
||||||
|
for i, s := range cs {
|
||||||
|
pc, err := parseConstraint(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = pc
|
||||||
|
}
|
||||||
|
or[k] = result
|
||||||
|
}
|
||||||
|
|
||||||
|
o := &Constraints{constraints: or}
|
||||||
|
return o, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check tests if a version satisfies the constraints.
|
||||||
|
func (cs Constraints) Check(v *Version) bool {
|
||||||
|
// loop over the ORs and check the inner ANDs
|
||||||
|
for _, o := range cs.constraints {
|
||||||
|
joy := true
|
||||||
|
for _, c := range o {
|
||||||
|
if !c.check(v) {
|
||||||
|
joy = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if joy {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate checks if a version satisfies a constraint. If not a slice of
|
||||||
|
// reasons for the failure are returned in addition to a bool.
|
||||||
|
func (cs Constraints) Validate(v *Version) (bool, []error) {
|
||||||
|
// loop over the ORs and check the inner ANDs
|
||||||
|
var e []error
|
||||||
|
|
||||||
|
// Capture the prerelease message only once. When it happens the first time
|
||||||
|
// this var is marked
|
||||||
|
var prerelesase bool
|
||||||
|
for _, o := range cs.constraints {
|
||||||
|
joy := true
|
||||||
|
for _, c := range o {
|
||||||
|
// Before running the check handle the case there the version is
|
||||||
|
// a prerelease and the check is not searching for prereleases.
|
||||||
|
if c.con.pre == "" && v.pre != "" {
|
||||||
|
if !prerelesase {
|
||||||
|
em := fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
||||||
|
e = append(e, em)
|
||||||
|
prerelesase = true
|
||||||
|
}
|
||||||
|
joy = false
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if !c.check(v) {
|
||||||
|
em := fmt.Errorf(c.msg, v, c.orig)
|
||||||
|
e = append(e, em)
|
||||||
|
joy = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if joy {
|
||||||
|
return true, []error{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, e
|
||||||
|
}
|
||||||
|
|
||||||
|
var constraintOps map[string]cfunc
|
||||||
|
var constraintMsg map[string]string
|
||||||
|
var constraintRegex *regexp.Regexp
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
constraintOps = map[string]cfunc{
|
||||||
|
"": constraintTildeOrEqual,
|
||||||
|
"=": constraintTildeOrEqual,
|
||||||
|
"!=": constraintNotEqual,
|
||||||
|
">": constraintGreaterThan,
|
||||||
|
"<": constraintLessThan,
|
||||||
|
">=": constraintGreaterThanEqual,
|
||||||
|
"=>": constraintGreaterThanEqual,
|
||||||
|
"<=": constraintLessThanEqual,
|
||||||
|
"=<": constraintLessThanEqual,
|
||||||
|
"~": constraintTilde,
|
||||||
|
"~>": constraintTilde,
|
||||||
|
"^": constraintCaret,
|
||||||
|
}
|
||||||
|
|
||||||
|
constraintMsg = map[string]string{
|
||||||
|
"": "%s is not equal to %s",
|
||||||
|
"=": "%s is not equal to %s",
|
||||||
|
"!=": "%s is equal to %s",
|
||||||
|
">": "%s is less than or equal to %s",
|
||||||
|
"<": "%s is greater than or equal to %s",
|
||||||
|
">=": "%s is less than %s",
|
||||||
|
"=>": "%s is less than %s",
|
||||||
|
"<=": "%s is greater than %s",
|
||||||
|
"=<": "%s is greater than %s",
|
||||||
|
"~": "%s does not have same major and minor version as %s",
|
||||||
|
"~>": "%s does not have same major and minor version as %s",
|
||||||
|
"^": "%s does not have same major version as %s",
|
||||||
|
}
|
||||||
|
|
||||||
|
ops := make([]string, 0, len(constraintOps))
|
||||||
|
for k := range constraintOps {
|
||||||
|
ops = append(ops, regexp.QuoteMeta(k))
|
||||||
|
}
|
||||||
|
|
||||||
|
constraintRegex = regexp.MustCompile(fmt.Sprintf(
|
||||||
|
`^\s*(%s)\s*(%s)\s*$`,
|
||||||
|
strings.Join(ops, "|"),
|
||||||
|
cvRegex))
|
||||||
|
|
||||||
|
constraintRangeRegex = regexp.MustCompile(fmt.Sprintf(
|
||||||
|
`\s*(%s)\s+-\s+(%s)\s*`,
|
||||||
|
cvRegex, cvRegex))
|
||||||
|
}
|
||||||
|
|
||||||
|
// An individual constraint
|
||||||
|
type constraint struct {
|
||||||
|
// The callback function for the restraint. It performs the logic for
|
||||||
|
// the constraint.
|
||||||
|
function cfunc
|
||||||
|
|
||||||
|
msg string
|
||||||
|
|
||||||
|
// The version used in the constraint check. For example, if a constraint
|
||||||
|
// is '<= 2.0.0' the con a version instance representing 2.0.0.
|
||||||
|
con *Version
|
||||||
|
|
||||||
|
// The original parsed version (e.g., 4.x from != 4.x)
|
||||||
|
orig string
|
||||||
|
|
||||||
|
// When an x is used as part of the version (e.g., 1.x)
|
||||||
|
minorDirty bool
|
||||||
|
dirty bool
|
||||||
|
patchDirty bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a version meets the constraint
|
||||||
|
func (c *constraint) check(v *Version) bool {
|
||||||
|
return c.function(v, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
type cfunc func(v *Version, c *constraint) bool
|
||||||
|
|
||||||
|
func parseConstraint(c string) (*constraint, error) {
|
||||||
|
m := constraintRegex.FindStringSubmatch(c)
|
||||||
|
if m == nil {
|
||||||
|
return nil, fmt.Errorf("improper constraint: %s", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
ver := m[2]
|
||||||
|
orig := ver
|
||||||
|
minorDirty := false
|
||||||
|
patchDirty := false
|
||||||
|
dirty := false
|
||||||
|
if isX(m[3]) {
|
||||||
|
ver = "0.0.0"
|
||||||
|
dirty = true
|
||||||
|
} else if isX(strings.TrimPrefix(m[4], ".")) || m[4] == "" {
|
||||||
|
minorDirty = true
|
||||||
|
dirty = true
|
||||||
|
ver = fmt.Sprintf("%s.0.0%s", m[3], m[6])
|
||||||
|
} else if isX(strings.TrimPrefix(m[5], ".")) {
|
||||||
|
dirty = true
|
||||||
|
patchDirty = true
|
||||||
|
ver = fmt.Sprintf("%s%s.0%s", m[3], m[4], m[6])
|
||||||
|
}
|
||||||
|
|
||||||
|
con, err := NewVersion(ver)
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
// The constraintRegex should catch any regex parsing errors. So,
|
||||||
|
// we should never get here.
|
||||||
|
return nil, errors.New("constraint Parser Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
cs := &constraint{
|
||||||
|
function: constraintOps[m[1]],
|
||||||
|
msg: constraintMsg[m[1]],
|
||||||
|
con: con,
|
||||||
|
orig: orig,
|
||||||
|
minorDirty: minorDirty,
|
||||||
|
patchDirty: patchDirty,
|
||||||
|
dirty: dirty,
|
||||||
|
}
|
||||||
|
return cs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constraint functions
|
||||||
|
func constraintNotEqual(v *Version, c *constraint) bool {
|
||||||
|
if c.dirty {
|
||||||
|
|
||||||
|
// If there is a pre-release on the version but the constraint isn't looking
|
||||||
|
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||||
|
// more details.
|
||||||
|
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.con.Major() != v.Major() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if c.con.Minor() != v.Minor() && !c.minorDirty {
|
||||||
|
return true
|
||||||
|
} else if c.minorDirty {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return !v.Equal(c.con)
|
||||||
|
}
|
||||||
|
|
||||||
|
func constraintGreaterThan(v *Version, c *constraint) bool {
|
||||||
|
|
||||||
|
// If there is a pre-release on the version but the constraint isn't looking
|
||||||
|
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||||
|
// more details.
|
||||||
|
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.Compare(c.con) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func constraintLessThan(v *Version, c *constraint) bool {
|
||||||
|
// If there is a pre-release on the version but the constraint isn't looking
|
||||||
|
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||||
|
// more details.
|
||||||
|
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.dirty {
|
||||||
|
return v.Compare(c.con) < 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Major() > c.con.Major() {
|
||||||
|
return false
|
||||||
|
} else if v.Minor() > c.con.Minor() && !c.minorDirty {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func constraintGreaterThanEqual(v *Version, c *constraint) bool {
|
||||||
|
|
||||||
|
// If there is a pre-release on the version but the constraint isn't looking
|
||||||
|
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||||
|
// more details.
|
||||||
|
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.Compare(c.con) >= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func constraintLessThanEqual(v *Version, c *constraint) bool {
|
||||||
|
// If there is a pre-release on the version but the constraint isn't looking
|
||||||
|
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||||
|
// more details.
|
||||||
|
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.dirty {
|
||||||
|
return v.Compare(c.con) <= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Major() > c.con.Major() {
|
||||||
|
return false
|
||||||
|
} else if v.Minor() > c.con.Minor() && !c.minorDirty {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ~*, ~>* --> >= 0.0.0 (any)
|
||||||
|
// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0, <3.0.0
|
||||||
|
// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0, <2.1.0
|
||||||
|
// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0
|
||||||
|
// ~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0
|
||||||
|
// ~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0
|
||||||
|
func constraintTilde(v *Version, c *constraint) bool {
|
||||||
|
// If there is a pre-release on the version but the constraint isn't looking
|
||||||
|
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||||
|
// more details.
|
||||||
|
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.LessThan(c.con) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ~0.0.0 is a special case where all constraints are accepted. It's
|
||||||
|
// equivalent to >= 0.0.0.
|
||||||
|
if c.con.Major() == 0 && c.con.Minor() == 0 && c.con.Patch() == 0 &&
|
||||||
|
!c.minorDirty && !c.patchDirty {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Major() != c.con.Major() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Minor() != c.con.Minor() && !c.minorDirty {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// When there is a .x (dirty) status it automatically opts in to ~. Otherwise
|
||||||
|
// it's a straight =
|
||||||
|
func constraintTildeOrEqual(v *Version, c *constraint) bool {
|
||||||
|
// If there is a pre-release on the version but the constraint isn't looking
|
||||||
|
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||||
|
// more details.
|
||||||
|
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.dirty {
|
||||||
|
c.msg = constraintMsg["~"]
|
||||||
|
return constraintTilde(v, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.Equal(c.con)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ^* --> (any)
|
||||||
|
// ^2, ^2.x, ^2.x.x --> >=2.0.0, <3.0.0
|
||||||
|
// ^2.0, ^2.0.x --> >=2.0.0, <3.0.0
|
||||||
|
// ^1.2, ^1.2.x --> >=1.2.0, <2.0.0
|
||||||
|
// ^1.2.3 --> >=1.2.3, <2.0.0
|
||||||
|
// ^1.2.0 --> >=1.2.0, <2.0.0
|
||||||
|
func constraintCaret(v *Version, c *constraint) bool {
|
||||||
|
// If there is a pre-release on the version but the constraint isn't looking
|
||||||
|
// for them assume that pre-releases are not compatible. See issue 21 for
|
||||||
|
// more details.
|
||||||
|
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.LessThan(c.con) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Major() != c.con.Major() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var constraintRangeRegex *regexp.Regexp
|
||||||
|
|
||||||
|
const cvRegex string = `v?([0-9|x|X|\*]+)(\.[0-9|x|X|\*]+)?(\.[0-9|x|X|\*]+)?` +
|
||||||
|
`(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
|
||||||
|
`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`
|
||||||
|
|
||||||
|
func isX(x string) bool {
|
||||||
|
switch x {
|
||||||
|
case "x", "*", "X":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func rewriteRange(i string) string {
|
||||||
|
m := constraintRangeRegex.FindAllStringSubmatch(i, -1)
|
||||||
|
if m == nil {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
o := i
|
||||||
|
for _, v := range m {
|
||||||
|
t := fmt.Sprintf(">= %s, <= %s", v[1], v[11])
|
||||||
|
o = strings.Replace(o, v[0], t, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return o
|
||||||
|
}
|
115
vendor/github.com/Masterminds/semver/doc.go
generated
vendored
Normal file
115
vendor/github.com/Masterminds/semver/doc.go
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
Package semver provides the ability to work with Semantic Versions (http://semver.org) in Go.
|
||||||
|
|
||||||
|
Specifically it provides the ability to:
|
||||||
|
|
||||||
|
* Parse semantic versions
|
||||||
|
* Sort semantic versions
|
||||||
|
* Check if a semantic version fits within a set of constraints
|
||||||
|
* Optionally work with a `v` prefix
|
||||||
|
|
||||||
|
Parsing Semantic Versions
|
||||||
|
|
||||||
|
To parse a semantic version use the `NewVersion` function. For example,
|
||||||
|
|
||||||
|
v, err := semver.NewVersion("1.2.3-beta.1+build345")
|
||||||
|
|
||||||
|
If there is an error the version wasn't parseable. The version object has methods
|
||||||
|
to get the parts of the version, compare it to other versions, convert the
|
||||||
|
version back into a string, and get the original string. For more details
|
||||||
|
please see the documentation at https://godoc.org/github.com/Masterminds/semver.
|
||||||
|
|
||||||
|
Sorting Semantic Versions
|
||||||
|
|
||||||
|
A set of versions can be sorted using the `sort` package from the standard library.
|
||||||
|
For example,
|
||||||
|
|
||||||
|
raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",}
|
||||||
|
vs := make([]*semver.Version, len(raw))
|
||||||
|
for i, r := range raw {
|
||||||
|
v, err := semver.NewVersion(r)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error parsing version: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vs[i] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(semver.Collection(vs))
|
||||||
|
|
||||||
|
Checking Version Constraints
|
||||||
|
|
||||||
|
Checking a version against version constraints is one of the most featureful
|
||||||
|
parts of the package.
|
||||||
|
|
||||||
|
c, err := semver.NewConstraint(">= 1.2.3")
|
||||||
|
if err != nil {
|
||||||
|
// Handle constraint not being parseable.
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := semver.NewVersion("1.3")
|
||||||
|
if err != nil {
|
||||||
|
// Handle version not being parseable.
|
||||||
|
}
|
||||||
|
// Check if the version meets the constraints. The a variable will be true.
|
||||||
|
a := c.Check(v)
|
||||||
|
|
||||||
|
Basic Comparisons
|
||||||
|
|
||||||
|
There are two elements to the comparisons. First, a comparison string is a list
|
||||||
|
of comma separated and comparisons. These are then separated by || separated or
|
||||||
|
comparisons. For example, `">= 1.2, < 3.0.0 || >= 4.2.3"` is looking for a
|
||||||
|
comparison that's greater than or equal to 1.2 and less than 3.0.0 or is
|
||||||
|
greater than or equal to 4.2.3.
|
||||||
|
|
||||||
|
The basic comparisons are:
|
||||||
|
|
||||||
|
* `=`: equal (aliased to no operator)
|
||||||
|
* `!=`: not equal
|
||||||
|
* `>`: greater than
|
||||||
|
* `<`: less than
|
||||||
|
* `>=`: greater than or equal to
|
||||||
|
* `<=`: less than or equal to
|
||||||
|
|
||||||
|
Hyphen Range Comparisons
|
||||||
|
|
||||||
|
There are multiple methods to handle ranges and the first is hyphens ranges.
|
||||||
|
These look like:
|
||||||
|
|
||||||
|
* `1.2 - 1.4.5` which is equivalent to `>= 1.2, <= 1.4.5`
|
||||||
|
* `2.3.4 - 4.5` which is equivalent to `>= 2.3.4, <= 4.5`
|
||||||
|
|
||||||
|
Wildcards In Comparisons
|
||||||
|
|
||||||
|
The `x`, `X`, and `*` characters can be used as a wildcard character. This works
|
||||||
|
for all comparison operators. When used on the `=` operator it falls
|
||||||
|
back to the pack level comparison (see tilde below). For example,
|
||||||
|
|
||||||
|
* `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
||||||
|
* `>= 1.2.x` is equivalent to `>= 1.2.0`
|
||||||
|
* `<= 2.x` is equivalent to `<= 3`
|
||||||
|
* `*` is equivalent to `>= 0.0.0`
|
||||||
|
|
||||||
|
Tilde Range Comparisons (Patch)
|
||||||
|
|
||||||
|
The tilde (`~`) comparison operator is for patch level ranges when a minor
|
||||||
|
version is specified and major level changes when the minor number is missing.
|
||||||
|
For example,
|
||||||
|
|
||||||
|
* `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0`
|
||||||
|
* `~1` is equivalent to `>= 1, < 2`
|
||||||
|
* `~2.3` is equivalent to `>= 2.3, < 2.4`
|
||||||
|
* `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
||||||
|
* `~1.x` is equivalent to `>= 1, < 2`
|
||||||
|
|
||||||
|
Caret Range Comparisons (Major)
|
||||||
|
|
||||||
|
The caret (`^`) comparison operator is for major level changes. This is useful
|
||||||
|
when comparisons of API versions as a major change is API breaking. For example,
|
||||||
|
|
||||||
|
* `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0`
|
||||||
|
* `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0`
|
||||||
|
* `^2.3` is equivalent to `>= 2.3, < 3`
|
||||||
|
* `^2.x` is equivalent to `>= 2.0.0, < 3`
|
||||||
|
*/
|
||||||
|
package semver
|
1
vendor/github.com/Masterminds/semver/v3/.gitignore
generated
vendored
1
vendor/github.com/Masterminds/semver/v3/.gitignore
generated
vendored
@ -1 +0,0 @@
|
|||||||
_fuzz/
|
|
26
vendor/github.com/Masterminds/semver/v3/.golangci.yml
generated
vendored
26
vendor/github.com/Masterminds/semver/v3/.golangci.yml
generated
vendored
@ -1,26 +0,0 @@
|
|||||||
run:
|
|
||||||
deadline: 2m
|
|
||||||
|
|
||||||
linters:
|
|
||||||
disable-all: true
|
|
||||||
enable:
|
|
||||||
- deadcode
|
|
||||||
- dupl
|
|
||||||
- errcheck
|
|
||||||
- gofmt
|
|
||||||
- goimports
|
|
||||||
- golint
|
|
||||||
- gosimple
|
|
||||||
- govet
|
|
||||||
- ineffassign
|
|
||||||
- misspell
|
|
||||||
- nakedret
|
|
||||||
- structcheck
|
|
||||||
- unused
|
|
||||||
- varcheck
|
|
||||||
|
|
||||||
linters-settings:
|
|
||||||
gofmt:
|
|
||||||
simplify: true
|
|
||||||
dupl:
|
|
||||||
threshold: 400
|
|
194
vendor/github.com/Masterminds/semver/v3/CHANGELOG.md
generated
vendored
194
vendor/github.com/Masterminds/semver/v3/CHANGELOG.md
generated
vendored
@ -1,194 +0,0 @@
|
|||||||
# Changelog
|
|
||||||
|
|
||||||
## 3.1.1 (2020-11-23)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- #158: Fixed issue with generated regex operation order that could cause problem
|
|
||||||
|
|
||||||
## 3.1.0 (2020-04-15)
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- #131: Add support for serializing/deserializing SQL (thanks @ryancurrah)
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- #148: More accurate validation messages on constraints
|
|
||||||
|
|
||||||
## 3.0.3 (2019-12-13)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- #141: Fixed issue with <= comparison
|
|
||||||
|
|
||||||
## 3.0.2 (2019-11-14)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- #134: Fixed broken constraint checking with ^0.0 (thanks @krmichelos)
|
|
||||||
|
|
||||||
## 3.0.1 (2019-09-13)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- #125: Fixes issue with module path for v3
|
|
||||||
|
|
||||||
## 3.0.0 (2019-09-12)
|
|
||||||
|
|
||||||
This is a major release of the semver package which includes API changes. The Go
|
|
||||||
API is compatible with ^1. The Go API was not changed because many people are using
|
|
||||||
`go get` without Go modules for their applications and API breaking changes cause
|
|
||||||
errors which we have or would need to support.
|
|
||||||
|
|
||||||
The changes in this release are the handling based on the data passed into the
|
|
||||||
functions. These are described in the added and changed sections below.
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- StrictNewVersion function. This is similar to NewVersion but will return an
|
|
||||||
error if the version passed in is not a strict semantic version. For example,
|
|
||||||
1.2.3 would pass but v1.2.3 or 1.2 would fail because they are not strictly
|
|
||||||
speaking semantic versions. This function is faster, performs fewer operations,
|
|
||||||
and uses fewer allocations than NewVersion.
|
|
||||||
- Fuzzing has been performed on NewVersion, StrictNewVersion, and NewConstraint.
|
|
||||||
The Makefile contains the operations used. For more information on you can start
|
|
||||||
on Wikipedia at https://en.wikipedia.org/wiki/Fuzzing
|
|
||||||
- Now using Go modules
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- NewVersion has proper prerelease and metadata validation with error messages
|
|
||||||
to signal an issue with either of them
|
|
||||||
- ^ now operates using a similar set of rules to npm/js and Rust/Cargo. If the
|
|
||||||
version is >=1 the ^ ranges works the same as v1. For major versions of 0 the
|
|
||||||
rules have changed. The minor version is treated as the stable version unless
|
|
||||||
a patch is specified and then it is equivalent to =. One difference from npm/js
|
|
||||||
is that prereleases there are only to a specific version (e.g. 1.2.3).
|
|
||||||
Prereleases here look over multiple versions and follow semantic version
|
|
||||||
ordering rules. This pattern now follows along with the expected and requested
|
|
||||||
handling of this packaged by numerous users.
|
|
||||||
|
|
||||||
## 1.5.0 (2019-09-11)
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- #103: Add basic fuzzing for `NewVersion()` (thanks @jesse-c)
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- #82: Clarify wildcard meaning in range constraints and update tests for it (thanks @greysteil)
|
|
||||||
- #83: Clarify caret operator range for pre-1.0.0 dependencies (thanks @greysteil)
|
|
||||||
- #72: Adding docs comment pointing to vert for a cli
|
|
||||||
- #71: Update the docs on pre-release comparator handling
|
|
||||||
- #89: Test with new go versions (thanks @thedevsaddam)
|
|
||||||
- #87: Added $ to ValidPrerelease for better validation (thanks @jeremycarroll)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- #78: Fix unchecked error in example code (thanks @ravron)
|
|
||||||
- #70: Fix the handling of pre-releases and the 0.0.0 release edge case
|
|
||||||
- #97: Fixed copyright file for proper display on GitHub
|
|
||||||
- #107: Fix handling prerelease when sorting alphanum and num
|
|
||||||
- #109: Fixed where Validate sometimes returns wrong message on error
|
|
||||||
|
|
||||||
## 1.4.2 (2018-04-10)
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- #72: Updated the docs to point to vert for a console appliaction
|
|
||||||
- #71: Update the docs on pre-release comparator handling
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- #70: Fix the handling of pre-releases and the 0.0.0 release edge case
|
|
||||||
|
|
||||||
## 1.4.1 (2018-04-02)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Fixed #64: Fix pre-release precedence issue (thanks @uudashr)
|
|
||||||
|
|
||||||
## 1.4.0 (2017-10-04)
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- #61: Update NewVersion to parse ints with a 64bit int size (thanks @zknill)
|
|
||||||
|
|
||||||
## 1.3.1 (2017-07-10)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Fixed #57: number comparisons in prerelease sometimes inaccurate
|
|
||||||
|
|
||||||
## 1.3.0 (2017-05-02)
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- #45: Added json (un)marshaling support (thanks @mh-cbon)
|
|
||||||
- Stability marker. See https://masterminds.github.io/stability/
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- #51: Fix handling of single digit tilde constraint (thanks @dgodd)
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- #55: The godoc icon moved from png to svg
|
|
||||||
|
|
||||||
## 1.2.3 (2017-04-03)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- #46: Fixed 0.x.x and 0.0.x in constraints being treated as *
|
|
||||||
|
|
||||||
## Release 1.2.2 (2016-12-13)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- #34: Fixed issue where hyphen range was not working with pre-release parsing.
|
|
||||||
|
|
||||||
## Release 1.2.1 (2016-11-28)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- #24: Fixed edge case issue where constraint "> 0" does not handle "0.0.1-alpha"
|
|
||||||
properly.
|
|
||||||
|
|
||||||
## Release 1.2.0 (2016-11-04)
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- #20: Added MustParse function for versions (thanks @adamreese)
|
|
||||||
- #15: Added increment methods on versions (thanks @mh-cbon)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Issue #21: Per the SemVer spec (section 9) a pre-release is unstable and
|
|
||||||
might not satisfy the intended compatibility. The change here ignores pre-releases
|
|
||||||
on constraint checks (e.g., ~ or ^) when a pre-release is not part of the
|
|
||||||
constraint. For example, `^1.2.3` will ignore pre-releases while
|
|
||||||
`^1.2.3-alpha` will include them.
|
|
||||||
|
|
||||||
## Release 1.1.1 (2016-06-30)
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Issue #9: Speed up version comparison performance (thanks @sdboyer)
|
|
||||||
- Issue #8: Added benchmarks (thanks @sdboyer)
|
|
||||||
- Updated Go Report Card URL to new location
|
|
||||||
- Updated Readme to add code snippet formatting (thanks @mh-cbon)
|
|
||||||
- Updating tagging to v[SemVer] structure for compatibility with other tools.
|
|
||||||
|
|
||||||
## Release 1.1.0 (2016-03-11)
|
|
||||||
|
|
||||||
- Issue #2: Implemented validation to provide reasons a versions failed a
|
|
||||||
constraint.
|
|
||||||
|
|
||||||
## Release 1.0.1 (2015-12-31)
|
|
||||||
|
|
||||||
- Fixed #1: * constraint failing on valid versions.
|
|
||||||
|
|
||||||
## Release 1.0.0 (2015-10-20)
|
|
||||||
|
|
||||||
- Initial release
|
|
37
vendor/github.com/Masterminds/semver/v3/Makefile
generated
vendored
37
vendor/github.com/Masterminds/semver/v3/Makefile
generated
vendored
@ -1,37 +0,0 @@
|
|||||||
GOPATH=$(shell go env GOPATH)
|
|
||||||
GOLANGCI_LINT=$(GOPATH)/bin/golangci-lint
|
|
||||||
GOFUZZBUILD = $(GOPATH)/bin/go-fuzz-build
|
|
||||||
GOFUZZ = $(GOPATH)/bin/go-fuzz
|
|
||||||
|
|
||||||
.PHONY: lint
|
|
||||||
lint: $(GOLANGCI_LINT)
|
|
||||||
@echo "==> Linting codebase"
|
|
||||||
@$(GOLANGCI_LINT) run
|
|
||||||
|
|
||||||
.PHONY: test
|
|
||||||
test:
|
|
||||||
@echo "==> Running tests"
|
|
||||||
GO111MODULE=on go test -v
|
|
||||||
|
|
||||||
.PHONY: test-cover
|
|
||||||
test-cover:
|
|
||||||
@echo "==> Running Tests with coverage"
|
|
||||||
GO111MODULE=on go test -cover .
|
|
||||||
|
|
||||||
.PHONY: fuzz
|
|
||||||
fuzz: $(GOFUZZBUILD) $(GOFUZZ)
|
|
||||||
@echo "==> Fuzz testing"
|
|
||||||
$(GOFUZZBUILD)
|
|
||||||
$(GOFUZZ) -workdir=_fuzz
|
|
||||||
|
|
||||||
$(GOLANGCI_LINT):
|
|
||||||
# Install golangci-lint. The configuration for it is in the .golangci.yml
|
|
||||||
# file in the root of the repository
|
|
||||||
echo ${GOPATH}
|
|
||||||
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.17.1
|
|
||||||
|
|
||||||
$(GOFUZZBUILD):
|
|
||||||
cd / && go get -u github.com/dvyukov/go-fuzz/go-fuzz-build
|
|
||||||
|
|
||||||
$(GOFUZZ):
|
|
||||||
cd / && go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-dep
|
|
244
vendor/github.com/Masterminds/semver/v3/README.md
generated
vendored
244
vendor/github.com/Masterminds/semver/v3/README.md
generated
vendored
@ -1,244 +0,0 @@
|
|||||||
# SemVer
|
|
||||||
|
|
||||||
The `semver` package provides the ability to work with [Semantic Versions](http://semver.org) in Go. Specifically it provides the ability to:
|
|
||||||
|
|
||||||
* Parse semantic versions
|
|
||||||
* Sort semantic versions
|
|
||||||
* Check if a semantic version fits within a set of constraints
|
|
||||||
* Optionally work with a `v` prefix
|
|
||||||
|
|
||||||
[![Stability:
|
|
||||||
Active](https://masterminds.github.io/stability/active.svg)](https://masterminds.github.io/stability/active.html)
|
|
||||||
[![](https://github.com/Masterminds/semver/workflows/Tests/badge.svg)](https://github.com/Masterminds/semver/actions)
|
|
||||||
[![GoDoc](https://img.shields.io/static/v1?label=godoc&message=reference&color=blue)](https://pkg.go.dev/github.com/Masterminds/semver/v3)
|
|
||||||
[![Go Report Card](https://goreportcard.com/badge/github.com/Masterminds/semver)](https://goreportcard.com/report/github.com/Masterminds/semver)
|
|
||||||
|
|
||||||
If you are looking for a command line tool for version comparisons please see
|
|
||||||
[vert](https://github.com/Masterminds/vert) which uses this library.
|
|
||||||
|
|
||||||
## Package Versions
|
|
||||||
|
|
||||||
There are three major versions fo the `semver` package.
|
|
||||||
|
|
||||||
* 3.x.x is the new stable and active version. This version is focused on constraint
|
|
||||||
compatibility for range handling in other tools from other languages. It has
|
|
||||||
a similar API to the v1 releases. The development of this version is on the master
|
|
||||||
branch. The documentation for this version is below.
|
|
||||||
* 2.x was developed primarily for [dep](https://github.com/golang/dep). There are
|
|
||||||
no tagged releases and the development was performed by [@sdboyer](https://github.com/sdboyer).
|
|
||||||
There are API breaking changes from v1. This version lives on the [2.x branch](https://github.com/Masterminds/semver/tree/2.x).
|
|
||||||
* 1.x.x is the most widely used version with numerous tagged releases. This is the
|
|
||||||
previous stable and is still maintained for bug fixes. The development, to fix
|
|
||||||
bugs, occurs on the release-1 branch. You can read the documentation [here](https://github.com/Masterminds/semver/blob/release-1/README.md).
|
|
||||||
|
|
||||||
## Parsing Semantic Versions
|
|
||||||
|
|
||||||
There are two functions that can parse semantic versions. The `StrictNewVersion`
|
|
||||||
function only parses valid version 2 semantic versions as outlined in the
|
|
||||||
specification. The `NewVersion` function attempts to coerce a version into a
|
|
||||||
semantic version and parse it. For example, if there is a leading v or a version
|
|
||||||
listed without all 3 parts (e.g. `v1.2`) it will attempt to coerce it into a valid
|
|
||||||
semantic version (e.g., 1.2.0). In both cases a `Version` object is returned
|
|
||||||
that can be sorted, compared, and used in constraints.
|
|
||||||
|
|
||||||
When parsing a version an error is returned if there is an issue parsing the
|
|
||||||
version. For example,
|
|
||||||
|
|
||||||
v, err := semver.NewVersion("1.2.3-beta.1+build345")
|
|
||||||
|
|
||||||
The version object has methods to get the parts of the version, compare it to
|
|
||||||
other versions, convert the version back into a string, and get the original
|
|
||||||
string. Getting the original string is useful if the semantic version was coerced
|
|
||||||
into a valid form.
|
|
||||||
|
|
||||||
## Sorting Semantic Versions
|
|
||||||
|
|
||||||
A set of versions can be sorted using the `sort` package from the standard library.
|
|
||||||
For example,
|
|
||||||
|
|
||||||
```go
|
|
||||||
raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",}
|
|
||||||
vs := make([]*semver.Version, len(raw))
|
|
||||||
for i, r := range raw {
|
|
||||||
v, err := semver.NewVersion(r)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error parsing version: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
vs[i] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Sort(semver.Collection(vs))
|
|
||||||
```
|
|
||||||
|
|
||||||
## Checking Version Constraints
|
|
||||||
|
|
||||||
There are two methods for comparing versions. One uses comparison methods on
|
|
||||||
`Version` instances and the other uses `Constraints`. There are some important
|
|
||||||
differences to notes between these two methods of comparison.
|
|
||||||
|
|
||||||
1. When two versions are compared using functions such as `Compare`, `LessThan`,
|
|
||||||
and others it will follow the specification and always include prereleases
|
|
||||||
within the comparison. It will provide an answer that is valid with the
|
|
||||||
comparison section of the spec at https://semver.org/#spec-item-11
|
|
||||||
2. When constraint checking is used for checks or validation it will follow a
|
|
||||||
different set of rules that are common for ranges with tools like npm/js
|
|
||||||
and Rust/Cargo. This includes considering prereleases to be invalid if the
|
|
||||||
ranges does not include one. If you want to have it include pre-releases a
|
|
||||||
simple solution is to include `-0` in your range.
|
|
||||||
3. Constraint ranges can have some complex rules including the shorthand use of
|
|
||||||
~ and ^. For more details on those see the options below.
|
|
||||||
|
|
||||||
There are differences between the two methods or checking versions because the
|
|
||||||
comparison methods on `Version` follow the specification while comparison ranges
|
|
||||||
are not part of the specification. Different packages and tools have taken it
|
|
||||||
upon themselves to come up with range rules. This has resulted in differences.
|
|
||||||
For example, npm/js and Cargo/Rust follow similar patterns while PHP has a
|
|
||||||
different pattern for ^. The comparison features in this package follow the
|
|
||||||
npm/js and Cargo/Rust lead because applications using it have followed similar
|
|
||||||
patters with their versions.
|
|
||||||
|
|
||||||
Checking a version against version constraints is one of the most featureful
|
|
||||||
parts of the package.
|
|
||||||
|
|
||||||
```go
|
|
||||||
c, err := semver.NewConstraint(">= 1.2.3")
|
|
||||||
if err != nil {
|
|
||||||
// Handle constraint not being parsable.
|
|
||||||
}
|
|
||||||
|
|
||||||
v, err := semver.NewVersion("1.3")
|
|
||||||
if err != nil {
|
|
||||||
// Handle version not being parsable.
|
|
||||||
}
|
|
||||||
// Check if the version meets the constraints. The a variable will be true.
|
|
||||||
a := c.Check(v)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Basic Comparisons
|
|
||||||
|
|
||||||
There are two elements to the comparisons. First, a comparison string is a list
|
|
||||||
of space or comma separated AND comparisons. These are then separated by || (OR)
|
|
||||||
comparisons. For example, `">= 1.2 < 3.0.0 || >= 4.2.3"` is looking for a
|
|
||||||
comparison that's greater than or equal to 1.2 and less than 3.0.0 or is
|
|
||||||
greater than or equal to 4.2.3.
|
|
||||||
|
|
||||||
The basic comparisons are:
|
|
||||||
|
|
||||||
* `=`: equal (aliased to no operator)
|
|
||||||
* `!=`: not equal
|
|
||||||
* `>`: greater than
|
|
||||||
* `<`: less than
|
|
||||||
* `>=`: greater than or equal to
|
|
||||||
* `<=`: less than or equal to
|
|
||||||
|
|
||||||
### Working With Prerelease Versions
|
|
||||||
|
|
||||||
Pre-releases, for those not familiar with them, are used for software releases
|
|
||||||
prior to stable or generally available releases. Examples of prereleases include
|
|
||||||
development, alpha, beta, and release candidate releases. A prerelease may be
|
|
||||||
a version such as `1.2.3-beta.1` while the stable release would be `1.2.3`. In the
|
|
||||||
order of precedence, prereleases come before their associated releases. In this
|
|
||||||
example `1.2.3-beta.1 < 1.2.3`.
|
|
||||||
|
|
||||||
According to the Semantic Version specification prereleases may not be
|
|
||||||
API compliant with their release counterpart. It says,
|
|
||||||
|
|
||||||
> A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version.
|
|
||||||
|
|
||||||
SemVer comparisons using constraints without a prerelease comparator will skip
|
|
||||||
prerelease versions. For example, `>=1.2.3` will skip prereleases when looking
|
|
||||||
at a list of releases while `>=1.2.3-0` will evaluate and find prereleases.
|
|
||||||
|
|
||||||
The reason for the `0` as a pre-release version in the example comparison is
|
|
||||||
because pre-releases can only contain ASCII alphanumerics and hyphens (along with
|
|
||||||
`.` separators), per the spec. Sorting happens in ASCII sort order, again per the
|
|
||||||
spec. The lowest character is a `0` in ASCII sort order
|
|
||||||
(see an [ASCII Table](http://www.asciitable.com/))
|
|
||||||
|
|
||||||
Understanding ASCII sort ordering is important because A-Z comes before a-z. That
|
|
||||||
means `>=1.2.3-BETA` will return `1.2.3-alpha`. What you might expect from case
|
|
||||||
sensitivity doesn't apply here. This is due to ASCII sort ordering which is what
|
|
||||||
the spec specifies.
|
|
||||||
|
|
||||||
### Hyphen Range Comparisons
|
|
||||||
|
|
||||||
There are multiple methods to handle ranges and the first is hyphens ranges.
|
|
||||||
These look like:
|
|
||||||
|
|
||||||
* `1.2 - 1.4.5` which is equivalent to `>= 1.2 <= 1.4.5`
|
|
||||||
* `2.3.4 - 4.5` which is equivalent to `>= 2.3.4 <= 4.5`
|
|
||||||
|
|
||||||
### Wildcards In Comparisons
|
|
||||||
|
|
||||||
The `x`, `X`, and `*` characters can be used as a wildcard character. This works
|
|
||||||
for all comparison operators. When used on the `=` operator it falls
|
|
||||||
back to the patch level comparison (see tilde below). For example,
|
|
||||||
|
|
||||||
* `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
|
||||||
* `>= 1.2.x` is equivalent to `>= 1.2.0`
|
|
||||||
* `<= 2.x` is equivalent to `< 3`
|
|
||||||
* `*` is equivalent to `>= 0.0.0`
|
|
||||||
|
|
||||||
### Tilde Range Comparisons (Patch)
|
|
||||||
|
|
||||||
The tilde (`~`) comparison operator is for patch level ranges when a minor
|
|
||||||
version is specified and major level changes when the minor number is missing.
|
|
||||||
For example,
|
|
||||||
|
|
||||||
* `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0`
|
|
||||||
* `~1` is equivalent to `>= 1, < 2`
|
|
||||||
* `~2.3` is equivalent to `>= 2.3, < 2.4`
|
|
||||||
* `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
|
||||||
* `~1.x` is equivalent to `>= 1, < 2`
|
|
||||||
|
|
||||||
### Caret Range Comparisons (Major)
|
|
||||||
|
|
||||||
The caret (`^`) comparison operator is for major level changes once a stable
|
|
||||||
(1.0.0) release has occurred. Prior to a 1.0.0 release the minor versions acts
|
|
||||||
as the API stability level. This is useful when comparisons of API versions as a
|
|
||||||
major change is API breaking. For example,
|
|
||||||
|
|
||||||
* `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0`
|
|
||||||
* `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0`
|
|
||||||
* `^2.3` is equivalent to `>= 2.3, < 3`
|
|
||||||
* `^2.x` is equivalent to `>= 2.0.0, < 3`
|
|
||||||
* `^0.2.3` is equivalent to `>=0.2.3 <0.3.0`
|
|
||||||
* `^0.2` is equivalent to `>=0.2.0 <0.3.0`
|
|
||||||
* `^0.0.3` is equivalent to `>=0.0.3 <0.0.4`
|
|
||||||
* `^0.0` is equivalent to `>=0.0.0 <0.1.0`
|
|
||||||
* `^0` is equivalent to `>=0.0.0 <1.0.0`
|
|
||||||
|
|
||||||
## Validation
|
|
||||||
|
|
||||||
In addition to testing a version against a constraint, a version can be validated
|
|
||||||
against a constraint. When validation fails a slice of errors containing why a
|
|
||||||
version didn't meet the constraint is returned. For example,
|
|
||||||
|
|
||||||
```go
|
|
||||||
c, err := semver.NewConstraint("<= 1.2.3, >= 1.4")
|
|
||||||
if err != nil {
|
|
||||||
// Handle constraint not being parseable.
|
|
||||||
}
|
|
||||||
|
|
||||||
v, err := semver.NewVersion("1.3")
|
|
||||||
if err != nil {
|
|
||||||
// Handle version not being parseable.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate a version against a constraint.
|
|
||||||
a, msgs := c.Validate(v)
|
|
||||||
// a is false
|
|
||||||
for _, m := range msgs {
|
|
||||||
fmt.Println(m)
|
|
||||||
|
|
||||||
// Loops over the errors which would read
|
|
||||||
// "1.3 is greater than 1.2.3"
|
|
||||||
// "1.3 is less than 1.4"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Contribute
|
|
||||||
|
|
||||||
If you find an issue or want to contribute please file an [issue](https://github.com/Masterminds/semver/issues)
|
|
||||||
or [create a pull request](https://github.com/Masterminds/semver/pulls).
|
|
568
vendor/github.com/Masterminds/semver/v3/constraints.go
generated
vendored
568
vendor/github.com/Masterminds/semver/v3/constraints.go
generated
vendored
@ -1,568 +0,0 @@
|
|||||||
package semver
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Constraints is one or more constraint that a semantic version can be
|
|
||||||
// checked against.
|
|
||||||
type Constraints struct {
|
|
||||||
constraints [][]*constraint
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewConstraint returns a Constraints instance that a Version instance can
|
|
||||||
// be checked against. If there is a parse error it will be returned.
|
|
||||||
func NewConstraint(c string) (*Constraints, error) {
|
|
||||||
|
|
||||||
// Rewrite - ranges into a comparison operation.
|
|
||||||
c = rewriteRange(c)
|
|
||||||
|
|
||||||
ors := strings.Split(c, "||")
|
|
||||||
or := make([][]*constraint, len(ors))
|
|
||||||
for k, v := range ors {
|
|
||||||
|
|
||||||
// TODO: Find a way to validate and fetch all the constraints in a simpler form
|
|
||||||
|
|
||||||
// Validate the segment
|
|
||||||
if !validConstraintRegex.MatchString(v) {
|
|
||||||
return nil, fmt.Errorf("improper constraint: %s", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
cs := findConstraintRegex.FindAllString(v, -1)
|
|
||||||
if cs == nil {
|
|
||||||
cs = append(cs, v)
|
|
||||||
}
|
|
||||||
result := make([]*constraint, len(cs))
|
|
||||||
for i, s := range cs {
|
|
||||||
pc, err := parseConstraint(s)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
result[i] = pc
|
|
||||||
}
|
|
||||||
or[k] = result
|
|
||||||
}
|
|
||||||
|
|
||||||
o := &Constraints{constraints: or}
|
|
||||||
return o, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check tests if a version satisfies the constraints.
|
|
||||||
func (cs Constraints) Check(v *Version) bool {
|
|
||||||
// TODO(mattfarina): For v4 of this library consolidate the Check and Validate
|
|
||||||
// functions as the underlying functions make that possible now.
|
|
||||||
// loop over the ORs and check the inner ANDs
|
|
||||||
for _, o := range cs.constraints {
|
|
||||||
joy := true
|
|
||||||
for _, c := range o {
|
|
||||||
if check, _ := c.check(v); !check {
|
|
||||||
joy = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if joy {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate checks if a version satisfies a constraint. If not a slice of
|
|
||||||
// reasons for the failure are returned in addition to a bool.
|
|
||||||
func (cs Constraints) Validate(v *Version) (bool, []error) {
|
|
||||||
// loop over the ORs and check the inner ANDs
|
|
||||||
var e []error
|
|
||||||
|
|
||||||
// Capture the prerelease message only once. When it happens the first time
|
|
||||||
// this var is marked
|
|
||||||
var prerelesase bool
|
|
||||||
for _, o := range cs.constraints {
|
|
||||||
joy := true
|
|
||||||
for _, c := range o {
|
|
||||||
// Before running the check handle the case there the version is
|
|
||||||
// a prerelease and the check is not searching for prereleases.
|
|
||||||
if c.con.pre == "" && v.pre != "" {
|
|
||||||
if !prerelesase {
|
|
||||||
em := fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
|
||||||
e = append(e, em)
|
|
||||||
prerelesase = true
|
|
||||||
}
|
|
||||||
joy = false
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if _, err := c.check(v); err != nil {
|
|
||||||
e = append(e, err)
|
|
||||||
joy = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if joy {
|
|
||||||
return true, []error{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cs Constraints) String() string {
|
|
||||||
buf := make([]string, len(cs.constraints))
|
|
||||||
var tmp bytes.Buffer
|
|
||||||
|
|
||||||
for k, v := range cs.constraints {
|
|
||||||
tmp.Reset()
|
|
||||||
vlen := len(v)
|
|
||||||
for kk, c := range v {
|
|
||||||
tmp.WriteString(c.string())
|
|
||||||
|
|
||||||
// Space separate the AND conditions
|
|
||||||
if vlen > 1 && kk < vlen-1 {
|
|
||||||
tmp.WriteString(" ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf[k] = tmp.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(buf, " || ")
|
|
||||||
}
|
|
||||||
|
|
||||||
var constraintOps map[string]cfunc
|
|
||||||
var constraintRegex *regexp.Regexp
|
|
||||||
var constraintRangeRegex *regexp.Regexp
|
|
||||||
|
|
||||||
// Used to find individual constraints within a multi-constraint string
|
|
||||||
var findConstraintRegex *regexp.Regexp
|
|
||||||
|
|
||||||
// Used to validate an segment of ANDs is valid
|
|
||||||
var validConstraintRegex *regexp.Regexp
|
|
||||||
|
|
||||||
const cvRegex string = `v?([0-9|x|X|\*]+)(\.[0-9|x|X|\*]+)?(\.[0-9|x|X|\*]+)?` +
|
|
||||||
`(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
|
|
||||||
`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
constraintOps = map[string]cfunc{
|
|
||||||
"": constraintTildeOrEqual,
|
|
||||||
"=": constraintTildeOrEqual,
|
|
||||||
"!=": constraintNotEqual,
|
|
||||||
">": constraintGreaterThan,
|
|
||||||
"<": constraintLessThan,
|
|
||||||
">=": constraintGreaterThanEqual,
|
|
||||||
"=>": constraintGreaterThanEqual,
|
|
||||||
"<=": constraintLessThanEqual,
|
|
||||||
"=<": constraintLessThanEqual,
|
|
||||||
"~": constraintTilde,
|
|
||||||
"~>": constraintTilde,
|
|
||||||
"^": constraintCaret,
|
|
||||||
}
|
|
||||||
|
|
||||||
ops := `=||!=|>|<|>=|=>|<=|=<|~|~>|\^`
|
|
||||||
|
|
||||||
constraintRegex = regexp.MustCompile(fmt.Sprintf(
|
|
||||||
`^\s*(%s)\s*(%s)\s*$`,
|
|
||||||
ops,
|
|
||||||
cvRegex))
|
|
||||||
|
|
||||||
constraintRangeRegex = regexp.MustCompile(fmt.Sprintf(
|
|
||||||
`\s*(%s)\s+-\s+(%s)\s*`,
|
|
||||||
cvRegex, cvRegex))
|
|
||||||
|
|
||||||
findConstraintRegex = regexp.MustCompile(fmt.Sprintf(
|
|
||||||
`(%s)\s*(%s)`,
|
|
||||||
ops,
|
|
||||||
cvRegex))
|
|
||||||
|
|
||||||
validConstraintRegex = regexp.MustCompile(fmt.Sprintf(
|
|
||||||
`^(\s*(%s)\s*(%s)\s*\,?)+$`,
|
|
||||||
ops,
|
|
||||||
cvRegex))
|
|
||||||
}
|
|
||||||
|
|
||||||
// An individual constraint
|
|
||||||
type constraint struct {
|
|
||||||
// The version used in the constraint check. For example, if a constraint
|
|
||||||
// is '<= 2.0.0' the con a version instance representing 2.0.0.
|
|
||||||
con *Version
|
|
||||||
|
|
||||||
// The original parsed version (e.g., 4.x from != 4.x)
|
|
||||||
orig string
|
|
||||||
|
|
||||||
// The original operator for the constraint
|
|
||||||
origfunc string
|
|
||||||
|
|
||||||
// When an x is used as part of the version (e.g., 1.x)
|
|
||||||
minorDirty bool
|
|
||||||
dirty bool
|
|
||||||
patchDirty bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if a version meets the constraint
|
|
||||||
func (c *constraint) check(v *Version) (bool, error) {
|
|
||||||
return constraintOps[c.origfunc](v, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// String prints an individual constraint into a string
|
|
||||||
func (c *constraint) string() string {
|
|
||||||
return c.origfunc + c.orig
|
|
||||||
}
|
|
||||||
|
|
||||||
type cfunc func(v *Version, c *constraint) (bool, error)
|
|
||||||
|
|
||||||
func parseConstraint(c string) (*constraint, error) {
|
|
||||||
if len(c) > 0 {
|
|
||||||
m := constraintRegex.FindStringSubmatch(c)
|
|
||||||
if m == nil {
|
|
||||||
return nil, fmt.Errorf("improper constraint: %s", c)
|
|
||||||
}
|
|
||||||
|
|
||||||
cs := &constraint{
|
|
||||||
orig: m[2],
|
|
||||||
origfunc: m[1],
|
|
||||||
}
|
|
||||||
|
|
||||||
ver := m[2]
|
|
||||||
minorDirty := false
|
|
||||||
patchDirty := false
|
|
||||||
dirty := false
|
|
||||||
if isX(m[3]) || m[3] == "" {
|
|
||||||
ver = "0.0.0"
|
|
||||||
dirty = true
|
|
||||||
} else if isX(strings.TrimPrefix(m[4], ".")) || m[4] == "" {
|
|
||||||
minorDirty = true
|
|
||||||
dirty = true
|
|
||||||
ver = fmt.Sprintf("%s.0.0%s", m[3], m[6])
|
|
||||||
} else if isX(strings.TrimPrefix(m[5], ".")) || m[5] == "" {
|
|
||||||
dirty = true
|
|
||||||
patchDirty = true
|
|
||||||
ver = fmt.Sprintf("%s%s.0%s", m[3], m[4], m[6])
|
|
||||||
}
|
|
||||||
|
|
||||||
con, err := NewVersion(ver)
|
|
||||||
if err != nil {
|
|
||||||
|
|
||||||
// The constraintRegex should catch any regex parsing errors. So,
|
|
||||||
// we should never get here.
|
|
||||||
return nil, errors.New("constraint Parser Error")
|
|
||||||
}
|
|
||||||
|
|
||||||
cs.con = con
|
|
||||||
cs.minorDirty = minorDirty
|
|
||||||
cs.patchDirty = patchDirty
|
|
||||||
cs.dirty = dirty
|
|
||||||
|
|
||||||
return cs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// The rest is the special case where an empty string was passed in which
|
|
||||||
// is equivalent to * or >=0.0.0
|
|
||||||
con, err := StrictNewVersion("0.0.0")
|
|
||||||
if err != nil {
|
|
||||||
|
|
||||||
// The constraintRegex should catch any regex parsing errors. So,
|
|
||||||
// we should never get here.
|
|
||||||
return nil, errors.New("constraint Parser Error")
|
|
||||||
}
|
|
||||||
|
|
||||||
cs := &constraint{
|
|
||||||
con: con,
|
|
||||||
orig: c,
|
|
||||||
origfunc: "",
|
|
||||||
minorDirty: false,
|
|
||||||
patchDirty: false,
|
|
||||||
dirty: true,
|
|
||||||
}
|
|
||||||
return cs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constraint functions
|
|
||||||
func constraintNotEqual(v *Version, c *constraint) (bool, error) {
|
|
||||||
if c.dirty {
|
|
||||||
|
|
||||||
// If there is a pre-release on the version but the constraint isn't looking
|
|
||||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
|
||||||
// more details.
|
|
||||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
|
||||||
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.con.Major() != v.Major() {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
if c.con.Minor() != v.Minor() && !c.minorDirty {
|
|
||||||
return true, nil
|
|
||||||
} else if c.minorDirty {
|
|
||||||
return false, fmt.Errorf("%s is equal to %s", v, c.orig)
|
|
||||||
} else if c.con.Patch() != v.Patch() && !c.patchDirty {
|
|
||||||
return true, nil
|
|
||||||
} else if c.patchDirty {
|
|
||||||
// Need to handle prereleases if present
|
|
||||||
if v.Prerelease() != "" || c.con.Prerelease() != "" {
|
|
||||||
eq := comparePrerelease(v.Prerelease(), c.con.Prerelease()) != 0
|
|
||||||
if eq {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf("%s is equal to %s", v, c.orig)
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf("%s is equal to %s", v, c.orig)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eq := v.Equal(c.con)
|
|
||||||
if eq {
|
|
||||||
return false, fmt.Errorf("%s is equal to %s", v, c.orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func constraintGreaterThan(v *Version, c *constraint) (bool, error) {
|
|
||||||
|
|
||||||
// If there is a pre-release on the version but the constraint isn't looking
|
|
||||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
|
||||||
// more details.
|
|
||||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
|
||||||
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
var eq bool
|
|
||||||
|
|
||||||
if !c.dirty {
|
|
||||||
eq = v.Compare(c.con) == 1
|
|
||||||
if eq {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.Major() > c.con.Major() {
|
|
||||||
return true, nil
|
|
||||||
} else if v.Major() < c.con.Major() {
|
|
||||||
return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
|
|
||||||
} else if c.minorDirty {
|
|
||||||
// This is a range case such as >11. When the version is something like
|
|
||||||
// 11.1.0 is it not > 11. For that we would need 12 or higher
|
|
||||||
return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
|
|
||||||
} else if c.patchDirty {
|
|
||||||
// This is for ranges such as >11.1. A version of 11.1.1 is not greater
|
|
||||||
// which one of 11.2.1 is greater
|
|
||||||
eq = v.Minor() > c.con.Minor()
|
|
||||||
if eq {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have gotten here we are not comparing pre-preleases and can use the
|
|
||||||
// Compare function to accomplish that.
|
|
||||||
eq = v.Compare(c.con) == 1
|
|
||||||
if eq {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
func constraintLessThan(v *Version, c *constraint) (bool, error) {
|
|
||||||
// If there is a pre-release on the version but the constraint isn't looking
|
|
||||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
|
||||||
// more details.
|
|
||||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
|
||||||
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
eq := v.Compare(c.con) < 0
|
|
||||||
if eq {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf("%s is greater than or equal to %s", v, c.orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
func constraintGreaterThanEqual(v *Version, c *constraint) (bool, error) {
|
|
||||||
|
|
||||||
// If there is a pre-release on the version but the constraint isn't looking
|
|
||||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
|
||||||
// more details.
|
|
||||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
|
||||||
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
eq := v.Compare(c.con) >= 0
|
|
||||||
if eq {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf("%s is less than %s", v, c.orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
func constraintLessThanEqual(v *Version, c *constraint) (bool, error) {
|
|
||||||
// If there is a pre-release on the version but the constraint isn't looking
|
|
||||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
|
||||||
// more details.
|
|
||||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
|
||||||
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
var eq bool
|
|
||||||
|
|
||||||
if !c.dirty {
|
|
||||||
eq = v.Compare(c.con) <= 0
|
|
||||||
if eq {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf("%s is greater than %s", v, c.orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.Major() > c.con.Major() {
|
|
||||||
return false, fmt.Errorf("%s is greater than %s", v, c.orig)
|
|
||||||
} else if v.Major() == c.con.Major() && v.Minor() > c.con.Minor() && !c.minorDirty {
|
|
||||||
return false, fmt.Errorf("%s is greater than %s", v, c.orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ~*, ~>* --> >= 0.0.0 (any)
|
|
||||||
// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0, <3.0.0
|
|
||||||
// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0, <2.1.0
|
|
||||||
// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0
|
|
||||||
// ~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0
|
|
||||||
// ~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0
|
|
||||||
func constraintTilde(v *Version, c *constraint) (bool, error) {
|
|
||||||
// If there is a pre-release on the version but the constraint isn't looking
|
|
||||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
|
||||||
// more details.
|
|
||||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
|
||||||
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.LessThan(c.con) {
|
|
||||||
return false, fmt.Errorf("%s is less than %s", v, c.orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ~0.0.0 is a special case where all constraints are accepted. It's
|
|
||||||
// equivalent to >= 0.0.0.
|
|
||||||
if c.con.Major() == 0 && c.con.Minor() == 0 && c.con.Patch() == 0 &&
|
|
||||||
!c.minorDirty && !c.patchDirty {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.Major() != c.con.Major() {
|
|
||||||
return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.Minor() != c.con.Minor() && !c.minorDirty {
|
|
||||||
return false, fmt.Errorf("%s does not have same major and minor version as %s", v, c.orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// When there is a .x (dirty) status it automatically opts in to ~. Otherwise
|
|
||||||
// it's a straight =
|
|
||||||
func constraintTildeOrEqual(v *Version, c *constraint) (bool, error) {
|
|
||||||
// If there is a pre-release on the version but the constraint isn't looking
|
|
||||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
|
||||||
// more details.
|
|
||||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
|
||||||
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.dirty {
|
|
||||||
return constraintTilde(v, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
eq := v.Equal(c.con)
|
|
||||||
if eq {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, fmt.Errorf("%s is not equal to %s", v, c.orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ^* --> (any)
|
|
||||||
// ^1.2.3 --> >=1.2.3 <2.0.0
|
|
||||||
// ^1.2 --> >=1.2.0 <2.0.0
|
|
||||||
// ^1 --> >=1.0.0 <2.0.0
|
|
||||||
// ^0.2.3 --> >=0.2.3 <0.3.0
|
|
||||||
// ^0.2 --> >=0.2.0 <0.3.0
|
|
||||||
// ^0.0.3 --> >=0.0.3 <0.0.4
|
|
||||||
// ^0.0 --> >=0.0.0 <0.1.0
|
|
||||||
// ^0 --> >=0.0.0 <1.0.0
|
|
||||||
func constraintCaret(v *Version, c *constraint) (bool, error) {
|
|
||||||
// If there is a pre-release on the version but the constraint isn't looking
|
|
||||||
// for them assume that pre-releases are not compatible. See issue 21 for
|
|
||||||
// more details.
|
|
||||||
if v.Prerelease() != "" && c.con.Prerelease() == "" {
|
|
||||||
return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This less than handles prereleases
|
|
||||||
if v.LessThan(c.con) {
|
|
||||||
return false, fmt.Errorf("%s is less than %s", v, c.orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
var eq bool
|
|
||||||
|
|
||||||
// ^ when the major > 0 is >=x.y.z < x+1
|
|
||||||
if c.con.Major() > 0 || c.minorDirty {
|
|
||||||
|
|
||||||
// ^ has to be within a major range for > 0. Everything less than was
|
|
||||||
// filtered out with the LessThan call above. This filters out those
|
|
||||||
// that greater but not within the same major range.
|
|
||||||
eq = v.Major() == c.con.Major()
|
|
||||||
if eq {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ^ when the major is 0 and minor > 0 is >=0.y.z < 0.y+1
|
|
||||||
if c.con.Major() == 0 && v.Major() > 0 {
|
|
||||||
return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig)
|
|
||||||
}
|
|
||||||
// If the con Minor is > 0 it is not dirty
|
|
||||||
if c.con.Minor() > 0 || c.patchDirty {
|
|
||||||
eq = v.Minor() == c.con.Minor()
|
|
||||||
if eq {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf("%s does not have same minor version as %s. Expected minor versions to match when constraint major version is 0", v, c.orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point the major is 0 and the minor is 0 and not dirty. The patch
|
|
||||||
// is not dirty so we need to check if they are equal. If they are not equal
|
|
||||||
eq = c.con.Patch() == v.Patch()
|
|
||||||
if eq {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf("%s does not equal %s. Expect version and constraint to equal when major and minor versions are 0", v, c.orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isX(x string) bool {
|
|
||||||
switch x {
|
|
||||||
case "x", "*", "X":
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func rewriteRange(i string) string {
|
|
||||||
m := constraintRangeRegex.FindAllStringSubmatch(i, -1)
|
|
||||||
if m == nil {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
o := i
|
|
||||||
for _, v := range m {
|
|
||||||
t := fmt.Sprintf(">= %s, <= %s", v[1], v[11])
|
|
||||||
o = strings.Replace(o, v[0], t, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return o
|
|
||||||
}
|
|
184
vendor/github.com/Masterminds/semver/v3/doc.go
generated
vendored
184
vendor/github.com/Masterminds/semver/v3/doc.go
generated
vendored
@ -1,184 +0,0 @@
|
|||||||
/*
|
|
||||||
Package semver provides the ability to work with Semantic Versions (http://semver.org) in Go.
|
|
||||||
|
|
||||||
Specifically it provides the ability to:
|
|
||||||
|
|
||||||
* Parse semantic versions
|
|
||||||
* Sort semantic versions
|
|
||||||
* Check if a semantic version fits within a set of constraints
|
|
||||||
* Optionally work with a `v` prefix
|
|
||||||
|
|
||||||
Parsing Semantic Versions
|
|
||||||
|
|
||||||
There are two functions that can parse semantic versions. The `StrictNewVersion`
|
|
||||||
function only parses valid version 2 semantic versions as outlined in the
|
|
||||||
specification. The `NewVersion` function attempts to coerce a version into a
|
|
||||||
semantic version and parse it. For example, if there is a leading v or a version
|
|
||||||
listed without all 3 parts (e.g. 1.2) it will attempt to coerce it into a valid
|
|
||||||
semantic version (e.g., 1.2.0). In both cases a `Version` object is returned
|
|
||||||
that can be sorted, compared, and used in constraints.
|
|
||||||
|
|
||||||
When parsing a version an optional error can be returned if there is an issue
|
|
||||||
parsing the version. For example,
|
|
||||||
|
|
||||||
v, err := semver.NewVersion("1.2.3-beta.1+b345")
|
|
||||||
|
|
||||||
The version object has methods to get the parts of the version, compare it to
|
|
||||||
other versions, convert the version back into a string, and get the original
|
|
||||||
string. For more details please see the documentation
|
|
||||||
at https://godoc.org/github.com/Masterminds/semver.
|
|
||||||
|
|
||||||
Sorting Semantic Versions
|
|
||||||
|
|
||||||
A set of versions can be sorted using the `sort` package from the standard library.
|
|
||||||
For example,
|
|
||||||
|
|
||||||
raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",}
|
|
||||||
vs := make([]*semver.Version, len(raw))
|
|
||||||
for i, r := range raw {
|
|
||||||
v, err := semver.NewVersion(r)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error parsing version: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
vs[i] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Sort(semver.Collection(vs))
|
|
||||||
|
|
||||||
Checking Version Constraints and Comparing Versions
|
|
||||||
|
|
||||||
There are two methods for comparing versions. One uses comparison methods on
|
|
||||||
`Version` instances and the other is using Constraints. There are some important
|
|
||||||
differences to notes between these two methods of comparison.
|
|
||||||
|
|
||||||
1. When two versions are compared using functions such as `Compare`, `LessThan`,
|
|
||||||
and others it will follow the specification and always include prereleases
|
|
||||||
within the comparison. It will provide an answer valid with the comparison
|
|
||||||
spec section at https://semver.org/#spec-item-11
|
|
||||||
2. When constraint checking is used for checks or validation it will follow a
|
|
||||||
different set of rules that are common for ranges with tools like npm/js
|
|
||||||
and Rust/Cargo. This includes considering prereleases to be invalid if the
|
|
||||||
ranges does not include on. If you want to have it include pre-releases a
|
|
||||||
simple solution is to include `-0` in your range.
|
|
||||||
3. Constraint ranges can have some complex rules including the shorthard use of
|
|
||||||
~ and ^. For more details on those see the options below.
|
|
||||||
|
|
||||||
There are differences between the two methods or checking versions because the
|
|
||||||
comparison methods on `Version` follow the specification while comparison ranges
|
|
||||||
are not part of the specification. Different packages and tools have taken it
|
|
||||||
upon themselves to come up with range rules. This has resulted in differences.
|
|
||||||
For example, npm/js and Cargo/Rust follow similar patterns which PHP has a
|
|
||||||
different pattern for ^. The comparison features in this package follow the
|
|
||||||
npm/js and Cargo/Rust lead because applications using it have followed similar
|
|
||||||
patters with their versions.
|
|
||||||
|
|
||||||
Checking a version against version constraints is one of the most featureful
|
|
||||||
parts of the package.
|
|
||||||
|
|
||||||
c, err := semver.NewConstraint(">= 1.2.3")
|
|
||||||
if err != nil {
|
|
||||||
// Handle constraint not being parsable.
|
|
||||||
}
|
|
||||||
|
|
||||||
v, err := semver.NewVersion("1.3")
|
|
||||||
if err != nil {
|
|
||||||
// Handle version not being parsable.
|
|
||||||
}
|
|
||||||
// Check if the version meets the constraints. The a variable will be true.
|
|
||||||
a := c.Check(v)
|
|
||||||
|
|
||||||
Basic Comparisons
|
|
||||||
|
|
||||||
There are two elements to the comparisons. First, a comparison string is a list
|
|
||||||
of comma or space separated AND comparisons. These are then separated by || (OR)
|
|
||||||
comparisons. For example, `">= 1.2 < 3.0.0 || >= 4.2.3"` is looking for a
|
|
||||||
comparison that's greater than or equal to 1.2 and less than 3.0.0 or is
|
|
||||||
greater than or equal to 4.2.3. This can also be written as
|
|
||||||
`">= 1.2, < 3.0.0 || >= 4.2.3"`
|
|
||||||
|
|
||||||
The basic comparisons are:
|
|
||||||
|
|
||||||
* `=`: equal (aliased to no operator)
|
|
||||||
* `!=`: not equal
|
|
||||||
* `>`: greater than
|
|
||||||
* `<`: less than
|
|
||||||
* `>=`: greater than or equal to
|
|
||||||
* `<=`: less than or equal to
|
|
||||||
|
|
||||||
Hyphen Range Comparisons
|
|
||||||
|
|
||||||
There are multiple methods to handle ranges and the first is hyphens ranges.
|
|
||||||
These look like:
|
|
||||||
|
|
||||||
* `1.2 - 1.4.5` which is equivalent to `>= 1.2, <= 1.4.5`
|
|
||||||
* `2.3.4 - 4.5` which is equivalent to `>= 2.3.4 <= 4.5`
|
|
||||||
|
|
||||||
Wildcards In Comparisons
|
|
||||||
|
|
||||||
The `x`, `X`, and `*` characters can be used as a wildcard character. This works
|
|
||||||
for all comparison operators. When used on the `=` operator it falls
|
|
||||||
back to the tilde operation. For example,
|
|
||||||
|
|
||||||
* `1.2.x` is equivalent to `>= 1.2.0 < 1.3.0`
|
|
||||||
* `>= 1.2.x` is equivalent to `>= 1.2.0`
|
|
||||||
* `<= 2.x` is equivalent to `<= 3`
|
|
||||||
* `*` is equivalent to `>= 0.0.0`
|
|
||||||
|
|
||||||
Tilde Range Comparisons (Patch)
|
|
||||||
|
|
||||||
The tilde (`~`) comparison operator is for patch level ranges when a minor
|
|
||||||
version is specified and major level changes when the minor number is missing.
|
|
||||||
For example,
|
|
||||||
|
|
||||||
* `~1.2.3` is equivalent to `>= 1.2.3 < 1.3.0`
|
|
||||||
* `~1` is equivalent to `>= 1, < 2`
|
|
||||||
* `~2.3` is equivalent to `>= 2.3 < 2.4`
|
|
||||||
* `~1.2.x` is equivalent to `>= 1.2.0 < 1.3.0`
|
|
||||||
* `~1.x` is equivalent to `>= 1 < 2`
|
|
||||||
|
|
||||||
Caret Range Comparisons (Major)
|
|
||||||
|
|
||||||
The caret (`^`) comparison operator is for major level changes once a stable
|
|
||||||
(1.0.0) release has occurred. Prior to a 1.0.0 release the minor versions acts
|
|
||||||
as the API stability level. This is useful when comparisons of API versions as a
|
|
||||||
major change is API breaking. For example,
|
|
||||||
|
|
||||||
* `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0`
|
|
||||||
* `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0`
|
|
||||||
* `^2.3` is equivalent to `>= 2.3, < 3`
|
|
||||||
* `^2.x` is equivalent to `>= 2.0.0, < 3`
|
|
||||||
* `^0.2.3` is equivalent to `>=0.2.3 <0.3.0`
|
|
||||||
* `^0.2` is equivalent to `>=0.2.0 <0.3.0`
|
|
||||||
* `^0.0.3` is equivalent to `>=0.0.3 <0.0.4`
|
|
||||||
* `^0.0` is equivalent to `>=0.0.0 <0.1.0`
|
|
||||||
* `^0` is equivalent to `>=0.0.0 <1.0.0`
|
|
||||||
|
|
||||||
Validation
|
|
||||||
|
|
||||||
In addition to testing a version against a constraint, a version can be validated
|
|
||||||
against a constraint. When validation fails a slice of errors containing why a
|
|
||||||
version didn't meet the constraint is returned. For example,
|
|
||||||
|
|
||||||
c, err := semver.NewConstraint("<= 1.2.3, >= 1.4")
|
|
||||||
if err != nil {
|
|
||||||
// Handle constraint not being parseable.
|
|
||||||
}
|
|
||||||
|
|
||||||
v, _ := semver.NewVersion("1.3")
|
|
||||||
if err != nil {
|
|
||||||
// Handle version not being parseable.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate a version against a constraint.
|
|
||||||
a, msgs := c.Validate(v)
|
|
||||||
// a is false
|
|
||||||
for _, m := range msgs {
|
|
||||||
fmt.Println(m)
|
|
||||||
|
|
||||||
// Loops over the errors which would read
|
|
||||||
// "1.3 is greater than 1.2.3"
|
|
||||||
// "1.3 is less than 1.4"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
package semver
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user