mirror of
https://gitee.com/johng/gf
synced 2026-06-07 18:26:02 +08:00
Compare commits
155 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d4b9ee4c61 | |||
| 50b5cd50bc | |||
| 53afbd0f05 | |||
| b6874eb66d | |||
| 7ff7de4643 | |||
| 5f148632d2 | |||
| c1325ef9a3 | |||
| d788b7ff5e | |||
| 66d0663dc5 | |||
| a56524ee05 | |||
| 1aa9f2809e | |||
| 261672e84c | |||
| 6a4e39e815 | |||
| 4af9ce8a81 | |||
| 5f146720fe | |||
| 67e6772d88 | |||
| 12e9febe9e | |||
| 676022eeb6 | |||
| 3a8fc1e70d | |||
| 0b6798acb5 | |||
| e721124b6c | |||
| b32eb30212 | |||
| 967a39ecbe | |||
| dfb7f5abfb | |||
| 56f5d5125b | |||
| 5083174a92 | |||
| 4a278dfd79 | |||
| 80d57ed8f9 | |||
| b742e222d6 | |||
| ae86f66545 | |||
| 45e4c9e16c | |||
| 8c07f1a42c | |||
| e6c97410ef | |||
| b1a55c7a32 | |||
| 1cd1449085 | |||
| 55690f3738 | |||
| 13f6fb1929 | |||
| e8088a6563 | |||
| e8051bad9a | |||
| d0d41a63a6 | |||
| 853b038a47 | |||
| 34946f6105 | |||
| 15d88c269d | |||
| cbbfd85eeb | |||
| adf90c876f | |||
| b4f76b8448 | |||
| ed858ebd4b | |||
| 272b9c7afd | |||
| 8dc8dd9756 | |||
| a64d1001e2 | |||
| ad737ded3c | |||
| ac6b0c0980 | |||
| b69e0ff9f7 | |||
| 0361f9f7de | |||
| 005668aca8 | |||
| 013f8b216a | |||
| 8ecfa91e5d | |||
| 117fc6eda2 | |||
| d66af122c7 | |||
| a7467945ca | |||
| 81d8aa55cd | |||
| 4a6630138d | |||
| 3adae3a9aa | |||
| 21ebf48072 | |||
| 2b90bcfab6 | |||
| 5f0641f348 | |||
| 38c9cac578 | |||
| 9ba49fa454 | |||
| 39fede66e6 | |||
| d984f1a9d8 | |||
| 28b8efe00c | |||
| 7b0fd6de9b | |||
| c0fa2e3a73 | |||
| 3f6669e2b7 | |||
| 6ff4ed84e5 | |||
| 5e72b03b0a | |||
| 4bb88027d8 | |||
| ae4f14c2e2 | |||
| 5a8b33fa09 | |||
| 5884a0e05f | |||
| 31e44062a8 | |||
| 87cb1c9b8e | |||
| 0266d24d0a | |||
| 0876e00eb8 | |||
| 85c4794ceb | |||
| e007bf35b2 | |||
| 74e968e93b | |||
| 18507fb836 | |||
| 3b245837b9 | |||
| a853984f52 | |||
| 00c544ee99 | |||
| e7b9e41a5e | |||
| e254b4f3c0 | |||
| b0c9c68c9c | |||
| 1030434ce6 | |||
| 2f08c4b00f | |||
| 4553f90a83 | |||
| ef7fec7e24 | |||
| 0a76b9c61b | |||
| fbeb8f81ac | |||
| 62af4f1c2c | |||
| ed43efe4fb | |||
| 1cb42c32e3 | |||
| 628b454ebc | |||
| 38a858d7d3 | |||
| 83b92ddfa4 | |||
| 7cd415b1df | |||
| d2113b4d23 | |||
| d445987f95 | |||
| 14d2d747f6 | |||
| 73dc8c9c4b | |||
| 576f1a798c | |||
| 78fa2d2e3b | |||
| 9402cc8c6a | |||
| 7d1a508ea9 | |||
| b84034b667 | |||
| 84b7cbd992 | |||
| bc8ca912ce | |||
| b61baa1efc | |||
| c4a5bc8584 | |||
| 8c71d579b5 | |||
| 2e8d8f63ff | |||
| 91b94878d3 | |||
| b000aa3dfe | |||
| 582c6eaef9 | |||
| 4f4109cdb6 | |||
| 9f12673631 | |||
| d37b75442d | |||
| ee58255418 | |||
| 033ba588c9 | |||
| 60d8283971 | |||
| ad90bc2809 | |||
| a1b9eca7b6 | |||
| c4a5b8ca94 | |||
| ab79134309 | |||
| 63c3e8396b | |||
| 1793bf0863 | |||
| 8e0e87877a | |||
| 425b31c6fd | |||
| 4da469325d | |||
| 33fdde6afd | |||
| ee6103418b | |||
| 038548c188 | |||
| ce8b536fca | |||
| 8e5a03f6c9 | |||
| 1c5fd1a1f7 | |||
| 2598745e50 | |||
| e756f284be | |||
| c6a02b850d | |||
| 55e8dbe9fd | |||
| 5efa5ebd2f | |||
| 4ebe4233fc | |||
| 35623b5abe | |||
| b617d399b6 | |||
| b96b5c3f7c |
11
.github/workflows/build_and_test.sh
vendored
11
.github/workflows/build_and_test.sh
vendored
@ -1,6 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
GOARCH=${{ matrix.goarch }}
|
||||
for file in `find . -name go.mod`; do
|
||||
dirpath=$(dirname $file)
|
||||
echo $dirpath
|
||||
@ -29,12 +28,22 @@ for file in `find . -name go.mod`; do
|
||||
fi
|
||||
fi
|
||||
|
||||
# package cmd/gf needs golang >= v1.18
|
||||
if [ "gf" = $(basename $dirpath) ]; then
|
||||
if ! go version|grep -q "1.18"; then
|
||||
echo "ignore example as go version: $(go version)"
|
||||
continue 1
|
||||
fi
|
||||
fi
|
||||
|
||||
cd $dirpath
|
||||
go mod tidy
|
||||
go build ./...
|
||||
go test ./... -race -coverprofile=coverage.out -covermode=atomic -coverpkg=./...,github.com/gogf/gf/... || exit 1
|
||||
|
||||
if grep -q "/gogf/gf/.*/v2" go.mod; then
|
||||
sed -i "s/gogf\/gf\(\/.*\)\/v2/gogf\/gf\/v2\1/g" coverage.out
|
||||
fi
|
||||
|
||||
cd -
|
||||
done
|
||||
14
.github/workflows/cli.yml
vendored
14
.github/workflows/cli.yml
vendored
@ -16,12 +16,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Github Code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set Up Golang Environment
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.17
|
||||
go-version: 1.20.3
|
||||
|
||||
- name: Build CLI Binary
|
||||
run: |
|
||||
@ -34,7 +34,7 @@ jobs:
|
||||
- name: Build CLI Binary For All Platform
|
||||
run: |
|
||||
cd cmd/gf
|
||||
gf build main.go -n gf -a all -s all
|
||||
gf build main.go -n gf -a amd64,386 -s windows,linux,darwin
|
||||
|
||||
- name: Move Files Before Release
|
||||
run: |
|
||||
@ -47,18 +47,18 @@ jobs:
|
||||
|
||||
- name: Create Github Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
uses: softprops/action-gh-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: GoFrame Release ${{ github.ref }}
|
||||
name: GoFrame Release ${{ github.ref }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
- name: Upload Release Asset
|
||||
id: upload-release-asset
|
||||
uses: alexellis/upload-assets@0.2.2
|
||||
uses: alexellis/upload-assets@0.4.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
|
||||
85
.github/workflows/gf.yml
vendored
85
.github/workflows/gf.yml
vendored
@ -35,9 +35,18 @@ jobs:
|
||||
|
||||
# Service containers to run with `code-test`
|
||||
services:
|
||||
# Etcd service.
|
||||
# docker run -d --name etcd -p 2379:2379 -e ALLOW_NONE_AUTHENTICATION=yes loads/etcd:3.4.24
|
||||
etcd:
|
||||
image: loads/etcd:3.4.24
|
||||
env:
|
||||
ALLOW_NONE_AUTHENTICATION: yes
|
||||
ports:
|
||||
- 2379:2379
|
||||
|
||||
# Redis backend server.
|
||||
redis:
|
||||
image : loads/redis:latest
|
||||
image : loads/redis:7.0
|
||||
options: >-
|
||||
--health-cmd "redis-cli ping"
|
||||
--health-interval 10s
|
||||
@ -54,11 +63,12 @@ jobs:
|
||||
MYSQL_DATABASE : test
|
||||
MYSQL_ROOT_PASSWORD: 12345678
|
||||
ports:
|
||||
# Maps tcp port 3306 on service container to the host
|
||||
- 3306:3306
|
||||
|
||||
# PostgreSQL backend server.
|
||||
# docker run -d --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=12345678 -e POSTGRES_USER=postgres -e POSTGRES_DB=test -v postgres:/Users/john/Temp/postgresql/data loads/postgres:13
|
||||
# docker run -d --name postgres -p 5432:5432 \
|
||||
# -e POSTGRES_PASSWORD=12345678 -e POSTGRES_USER=postgres -e POSTGRES_DB=test \
|
||||
# -v postgres:/Users/john/Temp/postgresql/data loads/postgres:13
|
||||
postgres:
|
||||
image: loads/postgres:13
|
||||
env:
|
||||
@ -76,8 +86,15 @@ jobs:
|
||||
--health-retries 5
|
||||
|
||||
# MSSQL backend server.
|
||||
# docker run -d --name mssql -p 1433:1433 \
|
||||
# -e ACCEPT_EULA=Y \
|
||||
# -e SA_PASSWORD=LoremIpsum86 \
|
||||
# -e MSSQL_DB=test \
|
||||
# -e MSSQL_USER=root \
|
||||
# -e MSSQL_PASSWORD=LoremIpsum86 \
|
||||
# loads/mssqldocker:14.0.3391.2
|
||||
mssql:
|
||||
image: loads/mssqldocker:latest
|
||||
image: loads/mssqldocker:14.0.3391.2
|
||||
env:
|
||||
ACCEPT_EULA: Y
|
||||
SA_PASSWORD: LoremIpsum86
|
||||
@ -94,17 +111,18 @@ jobs:
|
||||
--health-retries 10
|
||||
|
||||
# ClickHouse backend server.
|
||||
# docker run -d --name clickhouse -p 9000:9000 -p 8123:8123 -p 9001:9001 loads/clickhouse-server:latest
|
||||
# docker run -d --name clickhouse -p 9000:9000 -p 8123:8123 -p 9001:9001 loads/clickhouse-server:22.1.3.7
|
||||
clickhouse-server:
|
||||
image: loads/clickhouse-server:latest
|
||||
image: loads/clickhouse-server:22.1.3.7
|
||||
ports:
|
||||
- 9000:9000
|
||||
- 8123:8123
|
||||
- 9001:9001
|
||||
|
||||
# Polaris backend server.
|
||||
# docker run -d --name polaris -p 8090:8090 -p 8091:8091 -p 8093:8093 loads/polaris-server-standalone:1.11.2
|
||||
polaris:
|
||||
image: loads/polaris-server-standalone:latest
|
||||
image: loads/polaris-server-standalone:1.11.2
|
||||
ports:
|
||||
- 8090:8090
|
||||
- 8091:8091
|
||||
@ -112,7 +130,7 @@ jobs:
|
||||
|
||||
# Oracle 11g server
|
||||
oracle-server:
|
||||
image: loads/oracle-xe-11g-r2:latest
|
||||
image: loads/oracle-xe-11g-r2:11.2.0
|
||||
env:
|
||||
ORACLE_ALLOW_REMOTE: true
|
||||
ORACLE_SID: XE
|
||||
@ -122,50 +140,50 @@ jobs:
|
||||
- 1521:1521
|
||||
|
||||
# dm8 server
|
||||
# docker run -d --name dm -p 5236:5236 loads/dm:v8.1.2.128_ent_x86_64_ctm_pack4
|
||||
dm-server:
|
||||
image: loads/dm:v8.1.2.128_ent_x86_64_ctm_pack4
|
||||
ports:
|
||||
- 5236:5236
|
||||
|
||||
zookeeper:
|
||||
image: loads/zookeeper:3.8
|
||||
ports:
|
||||
- 2181:2181
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ "1.15", "1.16", "1.17", "1.18" ]
|
||||
goarch: [ "386", "amd64" ]
|
||||
|
||||
steps:
|
||||
# TODO: szenius/set-timezone update to node16
|
||||
- name: Setup Timezone
|
||||
uses: szenius/set-timezone@v1.0
|
||||
uses: szenius/set-timezone@v1.1
|
||||
with:
|
||||
timezoneLinux: "Asia/Shanghai"
|
||||
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Start Apollo Containers
|
||||
run: docker-compose -f ".github/workflows/apollo/docker-compose.yml" up -d --build
|
||||
|
||||
- name: Start Nacos Containers
|
||||
run: docker-compose -f ".github/workflows/nacos/docker-compose.yml" up -d --build
|
||||
|
||||
- name: Start Redis Cluster Containers
|
||||
run: docker-compose -f ".github/workflows/redis/docker-compose.yml" up -d --build
|
||||
|
||||
- name: Start Minikube
|
||||
uses: medyagh/setup-minikube@master
|
||||
|
||||
- name: Setup Golang ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
- name: Setup Golang caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
~/.cache/go-build
|
||||
~/Library/Caches/go-build
|
||||
~\AppData\Local\go-build
|
||||
key: ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-${{ matrix.go-version }}-
|
||||
|
||||
- name: Start redis cluster containers
|
||||
run: docker-compose -f ".github/workflows/redis/docker-compose.yml" up -d --build
|
||||
|
||||
- name: Start apollo containers
|
||||
run: docker-compose -f ".github/workflows/apollo/docker-compose.yml" up -d --build
|
||||
cache: true
|
||||
cache-dependency-path: '**/go.sum'
|
||||
|
||||
- name: Before Script
|
||||
run: bash .github/workflows/before_script.sh
|
||||
@ -173,14 +191,17 @@ jobs:
|
||||
- name: Build & Test
|
||||
run: bash .github/workflows/build_and_test.sh
|
||||
|
||||
- name: Stop redis cluster containers
|
||||
- name: Stop Redis Cluster Containers
|
||||
run: docker-compose -f ".github/workflows/redis/docker-compose.yml" down
|
||||
|
||||
- name: Stop apollo containers
|
||||
- name: Stop Apollo Containers
|
||||
run: docker-compose -f ".github/workflows/apollo/docker-compose.yml" down
|
||||
|
||||
- name: Stop Nacos Containers
|
||||
run: docker-compose -f ".github/workflows/nacos/docker-compose.yml" down
|
||||
|
||||
- name: Report Coverage
|
||||
uses: codecov/codecov-action@v2
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
flags: go-${{ matrix.go-version }}-${{ matrix.goarch }}
|
||||
|
||||
|
||||
50
.github/workflows/golangci-lint.yml
vendored
Normal file
50
.github/workflows/golangci-lint.yml
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
# Tencent is pleased to support the open source community by making Polaris available.
|
||||
#
|
||||
# Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
#
|
||||
# Licensed under the BSD 3-Clause License (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://opensource.org/licenses/BSD-3-Clause
|
||||
#
|
||||
# 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.
|
||||
|
||||
name: GolangCI-Lint
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- personal/**
|
||||
- feature/**
|
||||
- enhance/**
|
||||
- fix/**
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- personal/**
|
||||
- feature/**
|
||||
- enhance/**
|
||||
- fix/**
|
||||
|
||||
jobs:
|
||||
golangci:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.15.x,1.16.x,1.17.x,1.18.x]
|
||||
name: golangci-lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
- uses: actions/checkout@v3
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3.3.0
|
||||
with:
|
||||
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
|
||||
version: latest
|
||||
args: --timeout 3m0s
|
||||
2
.github/workflows/issue-check-inactive.yml
vendored
2
.github/workflows/issue-check-inactive.yml
vendored
@ -25,4 +25,4 @@ jobs:
|
||||
inactive-label: 'inactive'
|
||||
inactive-day: 7
|
||||
issue-state: open
|
||||
exclude-labels: 'bug,$exclude-empty'
|
||||
exclude-labels: 'bug,planned,$exclude-empty'
|
||||
19
.github/workflows/issue-translator.yml
vendored
Normal file
19
.github/workflows/issue-translator.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
# https://github.com/usthe/issues-translate-action
|
||||
name: 'Issue Translator'
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: usthe/issues-translate-action@v2.7
|
||||
with:
|
||||
IS_MODIFY_TITLE: true
|
||||
# not require, default false. Decide whether to modify the issue title
|
||||
# if true, the robot account @Issues-translate-bot must have modification permissions,
|
||||
# invite @Issues-translate-bot to your project or use your custom bot.
|
||||
CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
|
||||
40
.github/workflows/nacos/docker-compose.yml
vendored
Normal file
40
.github/workflows/nacos/docker-compose.yml
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
nacos:
|
||||
image: loads/nacos-server:v2.1.2
|
||||
container_name: nacos
|
||||
env_file:
|
||||
- ./env/nacos.env
|
||||
ports:
|
||||
- "8848:8848"
|
||||
- "9848:9848"
|
||||
- "9555:9555"
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl" ,"http://localhost:8848/nacos" ]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
|
||||
mysql:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./image/mysql/Dockerfile
|
||||
container_name: mysql
|
||||
env_file:
|
||||
- ./env/mysql.env
|
||||
healthcheck:
|
||||
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
|
||||
initializer:
|
||||
image: loads/curl:latest
|
||||
depends_on:
|
||||
nacos:
|
||||
condition: service_healthy
|
||||
command: [ "sh", "-c", "curl -X POST 'http://nacos:8848/nacos/v1/cs/configs?dataId=config.toml&group=test&content=%5Bserver%5D%0A%09address%3D%22%3A8000%22'" ]
|
||||
4
.github/workflows/nacos/env/mysql.env
vendored
Normal file
4
.github/workflows/nacos/env/mysql.env
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
MYSQL_ROOT_PASSWORD=root
|
||||
MYSQL_DATABASE=nacos_devtest
|
||||
MYSQL_USER=nacos
|
||||
MYSQL_PASSWORD=nacos
|
||||
9
.github/workflows/nacos/env/nacos.env
vendored
Normal file
9
.github/workflows/nacos/env/nacos.env
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
PREFER_HOST_MODE=hostname
|
||||
MODE=standalone
|
||||
SPRING_DATASOURCE_PLATFORM=mysql
|
||||
MYSQL_SERVICE_HOST=mysql
|
||||
MYSQL_SERVICE_DB_NAME=nacos_devtest
|
||||
MYSQL_SERVICE_PORT=3306
|
||||
MYSQL_SERVICE_USER=nacos
|
||||
MYSQL_SERVICE_PASSWORD=nacos
|
||||
MYSQL_SERVICE_DB_PARAM=characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
|
||||
5
.github/workflows/nacos/image/mysql/Dockerfile
vendored
Normal file
5
.github/workflows/nacos/image/mysql/Dockerfile
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
FROM loads/mysql:5.7
|
||||
ADD https://raw.githubusercontent.com/alibaba/nacos/develop/distribution/conf/mysql-schema.sql /docker-entrypoint-initdb.d/nacos-mysql.sql
|
||||
RUN chown -R mysql:mysql /docker-entrypoint-initdb.d/nacos-mysql.sql
|
||||
EXPOSE 3306
|
||||
CMD ["mysqld", "--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci"]
|
||||
6
.github/workflows/redis/docker-compose.yml
vendored
6
.github/workflows/redis/docker-compose.yml
vendored
@ -3,7 +3,7 @@ version: "2"
|
||||
services:
|
||||
redis-master:
|
||||
container_name: redis-master
|
||||
image: "loads/redis:7.0"
|
||||
image: "loads/redis:7.0-sentinel"
|
||||
environment:
|
||||
- REDIS_REPLICATION_MODE=master
|
||||
- REDIS_PASSWORD=111111
|
||||
@ -12,7 +12,7 @@ services:
|
||||
|
||||
redis-slave1:
|
||||
container_name: redis-slave1
|
||||
image: "loads/redis:7.0"
|
||||
image: "loads/redis:7.0-sentinel"
|
||||
environment:
|
||||
- REDIS_REPLICATION_MODE=slave
|
||||
- REDIS_MASTER_HOST=redis-master
|
||||
@ -27,7 +27,7 @@ services:
|
||||
|
||||
redis-slave2:
|
||||
container_name: redis-slave2
|
||||
image: "loads/redis:7.0"
|
||||
image: "loads/redis:7.0-sentinel"
|
||||
environment:
|
||||
- REDIS_REPLICATION_MODE=slave
|
||||
- REDIS_MASTER_HOST=redis-master
|
||||
|
||||
15
.github/workflows/tag.yml
vendored
15
.github/workflows/tag.yml
vendored
@ -17,9 +17,20 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Github Code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Auto Creating Tags
|
||||
- name: Update Dependencies
|
||||
run: make gftidy
|
||||
|
||||
- name: Commit & Push Changes
|
||||
uses: actions-js/push@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
author_name: TagRobot
|
||||
author_email: tagrobot@goframe.org
|
||||
message: "auto update version to ${{ github.ref_name }}"
|
||||
|
||||
- name: Auto Creating Tags For Contrib Packages
|
||||
run: |
|
||||
git config --global user.email "tagrobot@goframe.org"
|
||||
git config --global user.name "TagRobot"
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@ -7,13 +7,12 @@
|
||||
.settings/
|
||||
.vscode/
|
||||
vendor/
|
||||
composer.lock
|
||||
gitpush.sh
|
||||
pkg/
|
||||
bin/
|
||||
cbuild
|
||||
**/.DS_Store
|
||||
.test/
|
||||
cmd/gf/main
|
||||
cmd/gf/gf
|
||||
go.work
|
||||
go.work.sum
|
||||
temp/
|
||||
|
||||
290
.golangci.yml
290
.golangci.yml
@ -2,31 +2,56 @@
|
||||
## with their default values.
|
||||
|
||||
# See https://github.com/golangci/golangci-lint#config-file
|
||||
run:
|
||||
issues-exit-code: 1 #Default
|
||||
tests: true #Default
|
||||
# See https://golangci-lint.run/usage/configuration/
|
||||
|
||||
# Options for analysis running.
|
||||
run:
|
||||
# Exit code when at least one issue was found.
|
||||
# Default: 1
|
||||
issues-exit-code: 2
|
||||
|
||||
# Include test files or not.
|
||||
# Default: true
|
||||
tests: false
|
||||
|
||||
# Which dirs to skip: issues from them won't be reported.
|
||||
# Can use regexp here: `generated.*`, regexp is applied on full path.
|
||||
# Default value is empty list,
|
||||
# but default dirs are skipped independently of this option's value (see skip-dirs-use-default).
|
||||
# "/" will be replaced by current OS file path separator to properly work on Windows.
|
||||
skip-dirs: []
|
||||
|
||||
# Which files to skip: they will be analyzed, but issues from them won't be reported.
|
||||
# Default value is empty list,
|
||||
# but there is no need to include all autogenerated files,
|
||||
# we confidently recognize autogenerated files.
|
||||
# If it's not please let us know.
|
||||
# "/" will be replaced by current OS file path separator to properly work on Windows.
|
||||
skip-files: []
|
||||
|
||||
|
||||
# Main linters configurations.
|
||||
# See https://golangci-lint.run/usage/linters
|
||||
linters:
|
||||
# Disable everything by default so upgrades to not include new "default
|
||||
# enabled" linters.
|
||||
# Disable all default enabled linters.
|
||||
disable-all: true
|
||||
# Specifically enable linters we want to use.
|
||||
# Custom enable linters we want to use.
|
||||
enable:
|
||||
- deadcode
|
||||
- errcheck
|
||||
- gofmt
|
||||
- goimports
|
||||
- gosimple
|
||||
- govet
|
||||
- godot
|
||||
- ineffassign
|
||||
- misspell
|
||||
- revive
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- typecheck
|
||||
- unused
|
||||
- varcheck
|
||||
- errcheck # Errcheck is a program for checking for unchecked errors in go programs.
|
||||
- errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted.
|
||||
- funlen # Tool for detection of long functions
|
||||
- goconst # Finds repeated strings that could be replaced by a constant
|
||||
- gocritic # Provides diagnostics that check for bugs, performance and style issues.
|
||||
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
|
||||
- gosimple # Linter for Go source code that specializes in simplifying code
|
||||
- govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
|
||||
- misspell # Finds commonly misspelled English words in comments
|
||||
- nolintlint # Reports ill-formed or insufficient nolint directives
|
||||
- revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint.
|
||||
- staticcheck # It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary.
|
||||
- typecheck # Like the front-end of a Go compiler, parses and type-checks Go code
|
||||
- usestdlibvars # A linter that detect the possibility to use variables/constants from the Go standard library.
|
||||
- whitespace # Tool for detection of leading and trailing whitespace
|
||||
|
||||
|
||||
issues:
|
||||
@ -41,26 +66,217 @@ issues:
|
||||
text: "exported func.*returns unexported type.*which can be annoying to use"
|
||||
linters:
|
||||
- revive
|
||||
# https://github.com/go-critic/go-critic/issues/926
|
||||
- linters:
|
||||
- gocritic
|
||||
text: "unnecessaryDefer:"
|
||||
|
||||
|
||||
# https://golangci-lint.run/usage/linters
|
||||
linters-settings:
|
||||
# https://golangci-lint.run/usage/linters/#misspell
|
||||
misspell:
|
||||
locale: US
|
||||
ignore-words:
|
||||
- cancelled
|
||||
goimports:
|
||||
local-prefixes: github.com/gogf/gf
|
||||
godot:
|
||||
# Comments to be checked: `declarations`, `toplevel`, or `all`.
|
||||
# Default: declarations
|
||||
scope: toplevel
|
||||
exclude:
|
||||
# Exclude sentence fragments for lists.
|
||||
- '^[ ]*[-•]'
|
||||
# Exclude sentences prefixing a list.
|
||||
- ':$'
|
||||
# Check that each sentence ends with a period.
|
||||
# Default: true
|
||||
period: false
|
||||
# Check that each sentence starts with a capital letter.
|
||||
|
||||
# https://golangci-lint.run/usage/linters/#revive
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md
|
||||
revive:
|
||||
ignore-generated-header: true
|
||||
severity: error
|
||||
rules:
|
||||
- name: atomic
|
||||
- name: line-length-limit
|
||||
severity: error
|
||||
arguments: [ 380 ]
|
||||
- name: unhandled-error
|
||||
severity: warning
|
||||
disabled: true
|
||||
arguments: []
|
||||
- name: var-naming
|
||||
severity: warning
|
||||
disabled: true
|
||||
arguments:
|
||||
# AllowList
|
||||
- [ "ID","URL","IP","HTTP","JSON","API","UID","Id","Api","Uid","Http","Json","Ip","Url" ]
|
||||
# DenyList
|
||||
- [ "VM" ]
|
||||
- name: string-format
|
||||
severity: warning
|
||||
disabled: false
|
||||
arguments:
|
||||
- - 'core.WriteError[1].Message'
|
||||
- '/^([^A-Z]|$)/'
|
||||
- must not start with a capital letter
|
||||
- - 'fmt.Errorf[0]'
|
||||
- '/(^|[^\.!?])$/'
|
||||
- must not end in punctuation
|
||||
- - panic
|
||||
- '/^[^\n]*$/'
|
||||
- must not contain line breaks
|
||||
- name: function-result-limit
|
||||
severity: warning
|
||||
disabled: false
|
||||
arguments: [ 4 ]
|
||||
|
||||
# https://golangci-lint.run/usage/linters/#funlen
|
||||
funlen:
|
||||
# Checks the number of lines in a function.
|
||||
# If lower than 0, disable the check.
|
||||
# Default: 60
|
||||
lines: 330
|
||||
# Checks the number of statements in a function.
|
||||
# If lower than 0, disable the check.
|
||||
# Default: 40
|
||||
statements: -1
|
||||
|
||||
# https://golangci-lint.run/usage/linters/#goconst
|
||||
goconst:
|
||||
# Minimal length of string constant.
|
||||
# Default: 3
|
||||
min-len: 4
|
||||
# Minimum occurrences of constant string count to trigger issue.
|
||||
# Default: 3
|
||||
# For subsequent optimization, the value is reduced.
|
||||
min-occurrences: 30
|
||||
# Ignore test files.
|
||||
# Default: false
|
||||
capital: false
|
||||
ignore-tests: true
|
||||
# Look for existing constants matching the values.
|
||||
# Default: true
|
||||
match-constant: false
|
||||
# Search also for duplicated numbers.
|
||||
# Default: false
|
||||
numbers: true
|
||||
# Minimum value, only works with goconst.numbers
|
||||
# Default: 3
|
||||
min: 5
|
||||
# Maximum value, only works with goconst.numbers
|
||||
# Default: 3
|
||||
max: 20
|
||||
# Ignore when constant is not used as function argument.
|
||||
# Default: true
|
||||
ignore-calls: false
|
||||
|
||||
# https://golangci-lint.run/usage/linters/#gocritic
|
||||
gocritic:
|
||||
disabled-checks:
|
||||
- ifElseChain
|
||||
- assignOp
|
||||
- appendAssign
|
||||
- singleCaseSwitch
|
||||
- regexpMust
|
||||
- typeSwitchVar
|
||||
- elseif
|
||||
|
||||
# https://golangci-lint.run/usage/linters/#gosimple
|
||||
gosimple:
|
||||
# Select the Go version to target.
|
||||
# Default: 1.13
|
||||
# Deprecated: use the global `run.go` instead.
|
||||
go: "1.15"
|
||||
# Sxxxx checks in https://staticcheck.io/docs/configuration/options/#checks
|
||||
# Default: ["*"]
|
||||
checks: [
|
||||
"all", "-S1000", "-S1001", "-S1002", "-S1008", "-S1009", "-S1016", "-S1023", "-S1025", "-S1029", "-S1034", "-S1040"
|
||||
]
|
||||
|
||||
# https://golangci-lint.run/usage/linters/#govet
|
||||
govet:
|
||||
# Report about shadowed variables.
|
||||
# Default: false
|
||||
check-shadowing: true
|
||||
# Settings per analyzer.
|
||||
settings:
|
||||
# Analyzer name, run `go tool vet help` to see all analyzers.
|
||||
printf:
|
||||
# Comma-separated list of print function names to check (in addition to default, see `go tool vet help printf`).
|
||||
# Default: []
|
||||
funcs:
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
|
||||
# shadow:
|
||||
# Whether to be strict about shadowing; can be noisy.
|
||||
# Default: false
|
||||
# strict: false
|
||||
unusedresult:
|
||||
# Comma-separated list of functions whose results must be used
|
||||
# (in addition to defaults context.WithCancel,context.WithDeadline,context.WithTimeout,context.WithValue,
|
||||
# errors.New,fmt.Errorf,fmt.Sprint,fmt.Sprintf,sort.Reverse)
|
||||
# Default []
|
||||
funcs:
|
||||
- pkg.MyFunc
|
||||
- context.WithCancel
|
||||
# Comma-separated list of names of methods of type func() string whose results must be used
|
||||
# (in addition to default Error,String)
|
||||
# Default []
|
||||
stringmethods:
|
||||
- MyMethod
|
||||
# Enable all analyzers.
|
||||
# Default: false
|
||||
enable-all: true
|
||||
# Disable analyzers by name.
|
||||
# Run `go tool vet help` to see all analyzers.
|
||||
# Default: []
|
||||
disable:
|
||||
- asmdecl
|
||||
- assign
|
||||
- atomic
|
||||
- atomicalign
|
||||
- bools
|
||||
- buildtag
|
||||
- cgocall
|
||||
- composites
|
||||
- copylocks
|
||||
- deepequalerrors
|
||||
- errorsas
|
||||
- fieldalignment
|
||||
- findcall
|
||||
- framepointer
|
||||
- httpresponse
|
||||
- ifaceassert
|
||||
- loopclosure
|
||||
- lostcancel
|
||||
- nilfunc
|
||||
- nilness
|
||||
- reflectvaluecompare
|
||||
- shift
|
||||
- shadow
|
||||
- sigchanyzer
|
||||
- sortslice
|
||||
- stdmethods
|
||||
- stringintconv
|
||||
- structtag
|
||||
- testinggoroutine
|
||||
- tests
|
||||
- unmarshal
|
||||
- unreachable
|
||||
- unsafeptr
|
||||
- unusedwrite
|
||||
|
||||
# https://golangci-lint.run/usage/linters/#staticcheck
|
||||
staticcheck:
|
||||
# Select the Go version to target.
|
||||
# Default: "1.13"
|
||||
# Deprecated: use the global `run.go` instead.
|
||||
go: "1.15"
|
||||
# SAxxxx checks in https://staticcheck.io/docs/configuration/options/#checks
|
||||
# Default: ["*"]
|
||||
checks: [ "all","-SA1019","-SA4015","-SA1029","-SA1016","-SA9003","-SA4006","-SA6003" ]
|
||||
|
||||
# https://golangci-lint.run/usage/linters/#gofmt
|
||||
gofmt:
|
||||
# Simplify code: gofmt with `-s` option.
|
||||
# Default: true
|
||||
simplify: true
|
||||
# Apply the rewrite rules to the source before reformatting.
|
||||
# https://pkg.go.dev/cmd/gofmt
|
||||
# Default: []
|
||||
rewrite-rules: [ ]
|
||||
# - pattern: 'interface{}'
|
||||
# replacement: 'any'
|
||||
# - pattern: 'a[b:len(a)]'
|
||||
# replacement: 'a[b:]'
|
||||
|
||||
29
Makefile
29
Makefile
@ -1,4 +1,4 @@
|
||||
|
||||
SHELL := /bin/bash
|
||||
|
||||
.PHONY: tidy
|
||||
tidy:
|
||||
@ -11,3 +11,30 @@ tidy:
|
||||
cd -; \
|
||||
done
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
golangci-lint run
|
||||
|
||||
gftidy:
|
||||
$(eval files=$(shell find . -name go.mod))
|
||||
@set -e; \
|
||||
# GITHUB_REF_NAME=v2.4.0; \
|
||||
if [[ $$GITHUB_REF_NAME =~ "v" ]]; then \
|
||||
latestVersion=$$GITHUB_REF_NAME; \
|
||||
else \
|
||||
latestVersion=latest; \
|
||||
fi; \
|
||||
for file in ${files}; do \
|
||||
goModPath=$$(dirname $$file); \
|
||||
if [[ $$goModPath =~ "./contrib" || $$goModPath =~ "./cmd/gf" || $$goModPath =~ "./example" ]]; then \
|
||||
echo ""; \
|
||||
echo "processing dir: $$goModPath"; \
|
||||
# Do not modify the order of any of the following sentences \
|
||||
cd $$goModPath; \
|
||||
go mod tidy; \
|
||||
go list -f "{{if and (not .Indirect) (not .Main)}}{{.Path}}@$$latestVersion{{end}}" -m all | grep "^github.com/gogf/gf/contrib" | xargs -L1 go get -v; \
|
||||
go get -v github.com/gogf/gf/v2@$$latestVersion; \
|
||||
go mod tidy; \
|
||||
cd -; \
|
||||
fi \
|
||||
done
|
||||
37
README.MD
37
README.MD
@ -1,18 +1,20 @@
|
||||
# GoFrame
|
||||
|
||||
<div align=center>
|
||||
<img src="https://goframe.org/statics/image/gf-head-large.png" width="100"/>
|
||||
|
||||
[](https://godoc.org/github.com/gogf/gf)
|
||||
[](https://github.com/gogf/gf/actions/workflows/gf.yml)
|
||||
[](https://goreportcard.com/report/github.com/gogf/gf)
|
||||
[](https://codecov.io/gh/gogf/gf/branch/master)
|
||||
[](https://goreportcard.com/report/github.com/gogf/gf/v2)
|
||||
[](https://codecov.io/gh/gogf/gf)
|
||||
[](https://github.com/gogf/gf)
|
||||
[](https://github.com/gogf/gf)
|
||||
</div>
|
||||
|
||||
`GoFrame` is a modular, powerful, high-performance and enterprise-class application development framework of Golang.
|
||||
`GoFrame` is a modular, powerful, high-performance and enterprise-class application development framework of Golang.
|
||||
|
||||
# Features
|
||||
|
||||
- modular, loosely coupled design
|
||||
- rich components, out-of-the-box
|
||||
- automatic codes generating for efficiency
|
||||
@ -27,34 +29,37 @@
|
||||
- much, much more...ready to explore?
|
||||
|
||||
# Installation
|
||||
|
||||
Enter your repo. directory and execute following command:
|
||||
|
||||
## primary module
|
||||
|
||||
```bash
|
||||
go get -u -v github.com/gogf/gf/v2
|
||||
```
|
||||
|
||||
## cli tool
|
||||
|
||||
```bash
|
||||
go install github.com/gogf/gf/cmd/gf/v2
|
||||
```
|
||||
|
||||
# Limitation
|
||||
|
||||
```
|
||||
golang version >= 1.15
|
||||
```
|
||||
|
||||
# Architecture
|
||||
|
||||
<div align=center>
|
||||
<img src="https://goframe.org/download/attachments/1114119/arch.png"/>
|
||||
</div>
|
||||
|
||||
|
||||
# Documentation
|
||||
|
||||
* Chinese Official Site(中文官网): [https://goframe.org](https://goframe.org/display/gf)
|
||||
* GoDoc API: [https://pkg.go.dev/github.com/gogf/gf/v2](https://pkg.go.dev/github.com/gogf/gf/v2)
|
||||
|
||||
- Chinese Official Site(中文官网): [https://goframe.org](https://goframe.org/display/gf)
|
||||
- GoDoc API: [https://pkg.go.dev/github.com/gogf/gf/v2](https://pkg.go.dev/github.com/gogf/gf/v2)
|
||||
|
||||
# License
|
||||
|
||||
@ -76,32 +81,20 @@ golang version >= 1.15
|
||||
|
||||
> We list part of the users here, if your company or products are using `GoFrame`, please let us know [here](https://goframe.org/pages/viewpage.action?pageId=1114415).
|
||||
|
||||
|
||||
# Contributors
|
||||
|
||||
This project exists thanks to all the people who contribute. [[Contributors](https://github.com/gogf/gf/graphs/contributors)].
|
||||
<a href="https://github.com/gogf/gf/graphs/contributors"><img src="https://contributors-img.web.app/image?repo=gogf/gf" /></a>
|
||||
|
||||
|
||||
# Donators
|
||||
|
||||
If you love `GoFrame`, why not [buy developer a cup of coffee](https://goframe.org/pages/viewpage.action?pageId=1115633)?
|
||||
|
||||
# Sponsors
|
||||
|
||||
We appreciate any kind of sponsorship for `GoFrame` development. If you've got some interesting, please contact WeChat `389961817` / Email `john@goframe.org`.
|
||||
|
||||
|
||||
|
||||
# Thanks
|
||||
|
||||
<a href="https://www.jetbrains.com/?from=GoFrame"><img src="https://goframe.org/download/thumbnails/1114119/jetbrains.png" height="120" alt="JetBrains"/></a>
|
||||
<a href="https://www.atlassian.com/?from=GoFrame"><img src="https://goframe.org/download/attachments/1114119/atlassian.jpg" height="120" alt="Atlassian"/></a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -2,54 +2,67 @@
|
||||
|
||||
`gf` is a powerful CLI tool for building [GoFrame](https://goframe.org) application with convenience.
|
||||
|
||||
|
||||
## 1. Install
|
||||
|
||||
## 1) PreCompiled Binary
|
||||
You can also install `gf` tool using pre-built binaries: https://github.com/gogf/gf/releases
|
||||
|
||||
You can also install `gf` tool using pre-built binaries: <https://github.com/gogf/gf/releases>
|
||||
|
||||
1. `Mac` & `Linux`
|
||||
```shell
|
||||
|
||||
```shell
|
||||
wget -O gf https://github.com/gogf/gf/releases/latest/download/gf_$(go env GOOS)_$(go env GOARCH) && chmod +x gf && ./gf install -y && rm ./gf
|
||||
```
|
||||
```
|
||||
|
||||
> If you're using `zsh`, you might need rename your alias by command `alias gf=gf` to resolve the conflicts between `gf` and `git fetch`.
|
||||
|
||||
2. `Windows`
|
||||
Manually download, execute in command line it and then follow the instruction.
|
||||
|
||||
Manually download, execute it and then follow the instruction.
|
||||
3. Database support
|
||||
|
||||
3. Database `sqlite` and `oracle` are not support in `gf gen` command in default as it needs `cgo` and `gcc`, you can manually make some changes to the source codes and do the building.
|
||||
| DB | support | remarks |
|
||||
| :------: | :------: | :------: |
|
||||
| mysql | yes | - |
|
||||
| mariadb | yes | - |
|
||||
| tidb | yes | - |
|
||||
| mssql | yes | - |
|
||||
| oracle | yes | - |
|
||||
| pgsql | yes | - |
|
||||
| sqlite | yes | - |
|
||||
| clickhouse | no | manually make some changes to the [source codes](./internal/cmd/cmd_gen_dao.go) and do the building. |
|
||||
| dm | no | manually make some changes to the [source codes](./internal/cmd/cmd_gen_dao.go) and do the building. |
|
||||
|
||||
## 2) Manually Install
|
||||
|
||||
```shell
|
||||
```shell
|
||||
git clone https://github.com/gogf/gf && cd gf/cmd/gf && go install
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
## 2. Commands
|
||||
|
||||
```html
|
||||
$ gf
|
||||
USAGE
|
||||
gf COMMAND [OPTION]
|
||||
|
||||
COMMAND
|
||||
env show current Golang environment variables
|
||||
run running go codes with hot-compiled-like feature
|
||||
gen automatically generate go files for dao/do/entity/pb/pbentity
|
||||
tpl template parsing and building commands
|
||||
init create and initialize an empty GoFrame project
|
||||
pack packing any file/directory to a resource file, or a go file
|
||||
build cross-building go project for lots of platforms
|
||||
docker build docker image for current GoFrame project
|
||||
install install gf binary to system (might need root/admin permission)
|
||||
version show version information of current binary
|
||||
env show current Golang environment variables
|
||||
run running go codes with hot-compiled-like feature
|
||||
gen automatically generate go files for dao/do/entity/pb/pbentity
|
||||
tpl template parsing and building commands
|
||||
init create and initialize an empty GoFrame project
|
||||
pack packing any file/directory to a resource file, or a go file
|
||||
build cross-building go project for lots of platforms
|
||||
docker build docker image for current GoFrame project
|
||||
install install gf binary to system (might need root/admin permission)
|
||||
version show version information of current binary
|
||||
|
||||
OPTION
|
||||
-y, --yes all yes for all command without prompt ask
|
||||
-v, --version show version information of current binary
|
||||
-d, --debug show internal detailed debugging information
|
||||
-h, --help more information about this command
|
||||
-y, --yes all yes for all command without prompt ask
|
||||
-v, --version show version information of current binary
|
||||
-d, --debug show internal detailed debugging information
|
||||
-h, --help more information about this command
|
||||
|
||||
ADDITIONAL
|
||||
Use "gf COMMAND -h" for details about a command.
|
||||
@ -60,10 +73,3 @@ ADDITIONAL
|
||||
### 1). Command `gf run` returns `pipe: too many open files`
|
||||
|
||||
Please use `ulimit -n 65535` to enlarge your system configuration for max open files for current terminal shell session, and then `gf run`.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,20 +1,64 @@
|
||||
module github.com/gogf/gf/cmd/gf/v2
|
||||
|
||||
go 1.15
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.1.0
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.1.0
|
||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.1.0
|
||||
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.1.0
|
||||
github.com/gogf/gf/v2 v2.1.0
|
||||
github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.3.3
|
||||
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.3.3
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.3.3
|
||||
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.3.3
|
||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.3.3
|
||||
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.3.3
|
||||
github.com/gogf/gf/v2 v2.3.3
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
golang.org/x/tools v0.1.11
|
||||
golang.org/x/tools v0.7.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.1.0 // indirect
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.0.15 // indirect
|
||||
github.com/clbanning/mxj/v2 v2.5.5 // indirect
|
||||
github.com/denisenkom/go-mssqldb v0.11.0 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/glebarez/go-sqlite v1.17.3 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/grokify/html-strip-tags-go v0.0.1 // indirect
|
||||
github.com/lib/pq v1.10.4 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/mattn/go-colorable v0.1.9 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/paulmach/orb v0.7.1 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/sijms/go-ora/v2 v2.4.20 // indirect
|
||||
go.opentelemetry.io/otel v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.7.0 // indirect
|
||||
golang.org/x/crypto v0.1.0 // indirect
|
||||
golang.org/x/mod v0.9.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/libc v1.16.8 // indirect
|
||||
modernc.org/mathutil v1.4.1 // indirect
|
||||
modernc.org/memory v1.1.1 // indirect
|
||||
modernc.org/sqlite v1.17.3 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
github.com/gogf/gf/contrib/drivers/clickhouse/v2 => ../../contrib/drivers/clickhouse/
|
||||
github.com/gogf/gf/contrib/drivers/mssql/v2 => ../../contrib/drivers/mssql/
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 => ../../contrib/drivers/mysql/
|
||||
github.com/gogf/gf/contrib/drivers/oracle/v2 => ../../contrib/drivers/oracle/
|
||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 => ../../contrib/drivers/pgsql/
|
||||
github.com/gogf/gf/contrib/drivers/sqlite/v2 => ../../contrib/drivers/sqlite/
|
||||
github.com/gogf/gf/v2 => ../../
|
||||
|
||||
155
cmd/gf/go.sum
155
cmd/gf/go.sum
@ -1,24 +1,20 @@
|
||||
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
|
||||
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/ClickHouse/clickhouse-go v1.5.4/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.0.15 h1:lLAZliqrZEygkxosLaW1qHyeTb4Ho7fVCZ0WKCpLocU=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.0.15/go.mod h1:Z21o82zD8FFqefOQDg93c0XITlxGbTsWQuRm588Azkk=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
|
||||
github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E=
|
||||
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL/7ND8HI=
|
||||
github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/glebarez/go-sqlite v1.17.3 h1:Rji9ROVSTTfjuWD6j5B+8DtkNvPILoUC3xRhkQzGxvk=
|
||||
@ -28,40 +24,32 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
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.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
|
||||
github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
|
||||
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||
@ -73,35 +61,40 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615/go.mod h1:Ad7oeElCZqA1Ufj0U9/liOF4BtVepxRcTvr2ey7zTvM=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ=
|
||||
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||
github.com/paulmach/orb v0.7.1 h1:Zha++Z5OX/l168sqHK3k4z18LDvr+YAO/VjK0ReQ9rU=
|
||||
github.com/paulmach/orb v0.7.1/go.mod h1:FWRlTgl88VI1RBx/MkrwWDRhQ96ctqMCh8boXhmqB/A=
|
||||
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
||||
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
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/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
|
||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/sijms/go-ora/v2 v2.4.20 h1:9e3z7VLBQXRAHGiIda1GEFtRhfxata0LghyMZqvLKew=
|
||||
github.com/sijms/go-ora/v2 v2.4.20/go.mod h1:EHxlY6x7y9HAsdfumurRfTd+v8NrEOTR3Xl4FWlH6xk=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
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.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
|
||||
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM=
|
||||
go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=
|
||||
go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0=
|
||||
@ -112,92 +105,72 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
|
||||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191220220014-0732a990476f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/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-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 h1:GLw7MR8AfAG2GmGcmVgObFOHXYypgGjnGno25RDwn3Y=
|
||||
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY=
|
||||
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
|
||||
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
|
||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
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/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
||||
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
|
||||
modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=
|
||||
|
||||
@ -4,11 +4,13 @@ import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/service"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/service"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -38,6 +40,7 @@ type cGFInput struct {
|
||||
Version bool `short:"v" name:"version" brief:"show version information of current binary" orphan:"true"`
|
||||
Debug bool `short:"d" name:"debug" brief:"show internal detailed debugging information" orphan:"true"`
|
||||
}
|
||||
|
||||
type cGFOutput struct{}
|
||||
|
||||
func (c cGF) Index(ctx context.Context, in cGFInput) (out *cGFOutput, err error) {
|
||||
@ -46,17 +49,21 @@ func (c cGF) Index(ctx context.Context, in cGFInput) (out *cGFOutput, err error)
|
||||
_, err = Version.Index(ctx, cVersionInput{})
|
||||
return
|
||||
}
|
||||
answer := "n"
|
||||
// No argument or option, do installation checks.
|
||||
if !service.Install.IsInstalled() {
|
||||
if data, isInstalled := service.Install.IsInstalled(); !isInstalled {
|
||||
mlog.Print("hi, it seams it's the first time you installing gf cli.")
|
||||
s := gcmd.Scanf("do you want to install gf binary to your system? [y/n]: ")
|
||||
if strings.EqualFold(s, "y") {
|
||||
if err = service.Install.Run(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
gcmd.Scan("press `Enter` to exit...")
|
||||
answer = gcmd.Scanf("do you want to install gf(%s) binary to your system? [y/n]: ", gf.VERSION)
|
||||
} else if !data.IsSelf {
|
||||
mlog.Print("hi, you have installed gf cli.")
|
||||
answer = gcmd.Scanf("do you want to install gf(%s) binary to your system? [y/n]: ", gf.VERSION)
|
||||
}
|
||||
if strings.EqualFold(answer, "y") {
|
||||
if err = service.Install.Run(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
gcmd.Scan("press `Enter` to exit...")
|
||||
return
|
||||
}
|
||||
// Print help content.
|
||||
gcmd.CommandFromCtx(ctx).Print()
|
||||
|
||||
@ -9,7 +9,6 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/encoding/gbase64"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
@ -20,6 +19,8 @@ import (
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -123,10 +124,17 @@ type cBuildInput struct {
|
||||
PackSrc string `short:"ps" name:"packSrc" brief:"pack one or more folders into one go file before building"`
|
||||
PackDst string `short:"pd" name:"packDst" brief:"temporary go file path for pack, this go file will be automatically removed after built" d:"internal/packed/build_pack_data.go"`
|
||||
ExitWhenError bool `short:"ew" name:"exitWhenError" brief:"exit building when any error occurs, default is false" orphan:"true"`
|
||||
DumpENV bool `short:"de" name:"dumpEnv" brief:"dump current go build environment before building binary" orphan:"true"`
|
||||
}
|
||||
|
||||
type cBuildOutput struct{}
|
||||
|
||||
func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, err error) {
|
||||
// print used go env
|
||||
if in.DumpENV {
|
||||
_, _ = Env.Index(ctx, cEnvInput{})
|
||||
}
|
||||
|
||||
mlog.SetHeaderPrint(true)
|
||||
|
||||
mlog.Debugf(`build input: %+v`, in)
|
||||
@ -204,7 +212,9 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
|
||||
mlog.Printf(`remove the automatically generated resource go file: %s`, in.PackDst)
|
||||
}()
|
||||
}
|
||||
packCmd := fmt.Sprintf(`gf pack %s %s`, in.PackSrc, in.PackDst)
|
||||
// remove black space in separator.
|
||||
in.PackSrc, _ = gregex.ReplaceString(`,\s+`, `,`, in.PackSrc)
|
||||
packCmd := fmt.Sprintf(`gf pack %s %s --keepPath=true`, in.PackSrc, in.PackDst)
|
||||
mlog.Print(packCmd)
|
||||
gproc.MustShellRun(ctx, packCmd)
|
||||
}
|
||||
@ -232,7 +242,7 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
|
||||
if len(customSystems) > 0 && customSystems[0] != "all" && !gstr.InArray(customSystems, system) {
|
||||
continue
|
||||
}
|
||||
for arch, _ := range item {
|
||||
for arch := range item {
|
||||
if len(customArches) > 0 && customArches[0] != "all" && !gstr.InArray(customArches, arch) {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -5,12 +5,13 @@ import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -32,6 +33,7 @@ gf docker main.go
|
||||
gf docker main.go -t hub.docker.com/john/image:tag
|
||||
gf docker main.go -t hub.docker.com/john/image:tag
|
||||
gf docker main.go -p -t hub.docker.com/john/image:tag
|
||||
gf docker main.go -p -tp ["hub.docker.com/john","hub.docker.com/smith"] -tn image:tag
|
||||
`
|
||||
cDockerDc = `
|
||||
The "docker" command builds the GF project to a docker images.
|
||||
@ -44,6 +46,7 @@ You should have docker installed, and there must be a Dockerfile in the root of
|
||||
cDockerFileBrief = `file path of the Dockerfile. it's "manifest/docker/Dockerfile" in default`
|
||||
cDockerShellBrief = `path of the shell file which is executed before docker build`
|
||||
cDockerPushBrief = `auto push the docker image to docker registry if "-t" option passed`
|
||||
cDockerTagBrief = `full tag for this docker, pattern like "xxx.xxx.xxx/image:tag"`
|
||||
cDockerTagNameBrief = `tag name for this docker, pattern like "image:tag". this option is required with TagPrefixes`
|
||||
cDockerTagPrefixesBrief = `tag prefixes for this docker, which are used for docker push. this option is required with TagName`
|
||||
cDockerExtraBrief = `extra build options passed to "docker image"`
|
||||
@ -60,6 +63,7 @@ func init() {
|
||||
`cDockerShellBrief`: cDockerShellBrief,
|
||||
`cDockerBuildBrief`: cDockerBuildBrief,
|
||||
`cDockerPushBrief`: cDockerPushBrief,
|
||||
`cDockerTagBrief`: cDockerTagBrief,
|
||||
`cDockerTagNameBrief`: cDockerTagNameBrief,
|
||||
`cDockerTagPrefixesBrief`: cDockerTagPrefixesBrief,
|
||||
`cDockerExtraBrief`: cDockerExtraBrief,
|
||||
@ -72,11 +76,13 @@ type cDockerInput struct {
|
||||
File string `name:"file" short:"f" brief:"{cDockerFileBrief}" d:"manifest/docker/Dockerfile"`
|
||||
Shell string `name:"shell" short:"s" brief:"{cDockerShellBrief}" d:"manifest/docker/docker.sh"`
|
||||
Build string `name:"build" short:"b" brief:"{cDockerBuildBrief}" d:"-a amd64 -s linux"`
|
||||
Tag string `name:"tag" short:"t" brief:"{cDockerTagBrief}"`
|
||||
TagName string `name:"tagName" short:"tn" brief:"{cDockerTagNameBrief}" v:"required-with:TagPrefixes"`
|
||||
TagPrefixes []string `name:"tagPrefixes" short:"tp" brief:"{cDockerTagPrefixesBrief}" v:"required-with:TagName"`
|
||||
Push bool `name:"push" short:"p" brief:"{cDockerPushBrief}" orphan:"true"`
|
||||
Extra string `name:"extra" short:"e" brief:"{cDockerExtraBrief}"`
|
||||
}
|
||||
|
||||
type cDockerOutput struct{}
|
||||
|
||||
func (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput, err error) {
|
||||
@ -112,7 +118,7 @@ func (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput
|
||||
}
|
||||
}
|
||||
if len(dockerTags) == 0 {
|
||||
dockerTags = []string{""}
|
||||
dockerTags = []string{in.Tag}
|
||||
}
|
||||
for i, dockerTag := range dockerTags {
|
||||
if i > 0 {
|
||||
|
||||
@ -4,12 +4,13 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -23,6 +24,7 @@ type cEnv struct {
|
||||
type cEnvInput struct {
|
||||
g.Meta `name:"env"`
|
||||
}
|
||||
|
||||
type cEnvOutput struct{}
|
||||
|
||||
func (c cEnv) Index(ctx context.Context, in cEnvInput) (out *cEnvOutput, err error) {
|
||||
|
||||
121
cmd/gf/internal/cmd/cmd_fix.go
Normal file
121
cmd/gf/internal/cmd/cmd_fix.go
Normal file
@ -0,0 +1,121 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
var (
|
||||
Fix = cFix{}
|
||||
)
|
||||
|
||||
type cFix struct {
|
||||
g.Meta `name:"fix" brief:"auto fixing codes after upgrading to new GoFrame version" usage:"gf fix" `
|
||||
}
|
||||
|
||||
type cFixInput struct {
|
||||
g.Meta `name:"fix"`
|
||||
Path string `name:"path" short:"p" brief:"directory path, it uses current working directory in default"`
|
||||
Version string `name:"version" short:"v" brief:"custom specified version to fix, leave it empty to auto detect"`
|
||||
}
|
||||
|
||||
type cFixOutput struct{}
|
||||
|
||||
type cFixItem struct {
|
||||
Version string
|
||||
Func func(version string) error
|
||||
}
|
||||
|
||||
func (c cFix) Index(ctx context.Context, in cFixInput) (out *cFixOutput, err error) {
|
||||
|
||||
if in.Path == "" {
|
||||
in.Path = gfile.Pwd()
|
||||
}
|
||||
if in.Version == "" {
|
||||
in.Version, err = c.autoDetectVersion(in)
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
if in.Version == "" {
|
||||
mlog.Print(`no GoFrame usage found, exit fixing`)
|
||||
return
|
||||
}
|
||||
mlog.Debugf(`current GoFrame version auto detect "%s"`, in.Version)
|
||||
}
|
||||
|
||||
if !gproc.IsChild() {
|
||||
mlog.Printf(`start auto fixing directory path "%s"...`, in.Path)
|
||||
defer mlog.Print(`done!`)
|
||||
}
|
||||
|
||||
err = c.doFix(in)
|
||||
return
|
||||
}
|
||||
|
||||
func (c cFix) doFix(in cFixInput) (err error) {
|
||||
|
||||
var items = []cFixItem{
|
||||
{Version: "v2.3", Func: c.doFixV23},
|
||||
}
|
||||
for _, item := range items {
|
||||
if gstr.CompareVersionGo(in.Version, item.Version) < 0 {
|
||||
mlog.Debugf(
|
||||
`current GoFrame or contrib package version "%s" is lesser than "%s", nothing to do`,
|
||||
in.Version, item.Version,
|
||||
)
|
||||
continue
|
||||
}
|
||||
if err = item.Func(in.Version); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// doFixV23 fixes code when upgrading to GoFrame v2.3.
|
||||
func (c cFix) doFixV23(version string) error {
|
||||
replaceFunc := func(path, content string) string {
|
||||
// gdb.TX from struct to interface.
|
||||
content = gstr.Replace(content, "*gdb.TX", "gdb.TX")
|
||||
// function name changes for package gtcp/gudp.
|
||||
if gstr.Contains(content, "/gf/v2/net/gtcp") || gstr.Contains(content, "/gf/v2/net/gudp") {
|
||||
content = gstr.ReplaceByMap(content, g.MapStrStr{
|
||||
".SetSendDeadline": ".SetDeadlineSend",
|
||||
".SetReceiveDeadline": ".SetDeadlineRecv",
|
||||
".SetReceiveBufferWait": ".SetBufferWaitRecv",
|
||||
})
|
||||
}
|
||||
return content
|
||||
}
|
||||
return gfile.ReplaceDirFunc(replaceFunc, ".", "*.go", true)
|
||||
}
|
||||
|
||||
func (c cFix) autoDetectVersion(in cFixInput) (string, error) {
|
||||
var (
|
||||
err error
|
||||
path = gfile.Join(in.Path, "go.mod")
|
||||
version string
|
||||
)
|
||||
if !gfile.Exists(path) {
|
||||
return "", gerror.Newf(`"%s" not found in current working directory`, path)
|
||||
}
|
||||
err = gfile.ReadLines(path, func(line string) error {
|
||||
array := gstr.SplitAndTrim(line, " ")
|
||||
if len(array) > 0 {
|
||||
if gstr.HasPrefix(array[0], gfPackage) {
|
||||
version = array[1]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
return version, nil
|
||||
}
|
||||
@ -1,11 +1,12 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
_ "github.com/gogf/gf/contrib/drivers/clickhouse/v2"
|
||||
_ "github.com/gogf/gf/contrib/drivers/mssql/v2"
|
||||
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
|
||||
_ "github.com/gogf/gf/contrib/drivers/oracle/v2"
|
||||
_ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
|
||||
_ "github.com/gogf/gf/contrib/drivers/sqlite/v2"
|
||||
//_ "github.com/gogf/gf/contrib/drivers/oracle/v2"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/gendao"
|
||||
)
|
||||
|
||||
@ -1,79 +1,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/container/gset"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/genv"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
)
|
||||
import "github.com/gogf/gf/cmd/gf/v2/internal/cmd/genpb"
|
||||
|
||||
type (
|
||||
cGenPb struct{}
|
||||
cGenPbInput struct {
|
||||
g.Meta `name:"pb" brief:"parse proto files and generate protobuf go files"`
|
||||
}
|
||||
cGenPbOutput struct{}
|
||||
cGenPb = genpb.CGenPb
|
||||
)
|
||||
|
||||
func (c cGenPb) Pb(ctx context.Context, in cGenPbInput) (out *cGenPbOutput, err error) {
|
||||
// Necessary check.
|
||||
if gproc.SearchBinary("protoc") == "" {
|
||||
mlog.Fatalf(`command "protoc" not found in your environment, please install protoc first to proceed this command`)
|
||||
}
|
||||
|
||||
// protocol fold checks.
|
||||
protoFolder := "protocol"
|
||||
if !gfile.Exists(protoFolder) {
|
||||
mlog.Fatalf(`proto files folder "%s" does not exist`, protoFolder)
|
||||
}
|
||||
// folder scanning.
|
||||
files, err := gfile.ScanDirFile(protoFolder, "*.proto", true)
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
if len(files) == 0 {
|
||||
mlog.Fatalf(`no proto files found in folder "%s"`, protoFolder)
|
||||
}
|
||||
dirSet := gset.NewStrSet()
|
||||
for _, file := range files {
|
||||
dirSet.Add(gfile.Dir(file))
|
||||
}
|
||||
var (
|
||||
servicePath = gfile.RealPath(".")
|
||||
goPathSrc = gfile.RealPath(gfile.Join(genv.Get("GOPATH").String(), "src"))
|
||||
)
|
||||
dirSet.Iterator(func(protoDirPath string) bool {
|
||||
parsingCommand := fmt.Sprintf(
|
||||
"protoc --gofast_out=plugins=grpc:. %s/*.proto -I%s",
|
||||
protoDirPath,
|
||||
servicePath,
|
||||
)
|
||||
if goPathSrc != "" {
|
||||
parsingCommand += " -I" + goPathSrc
|
||||
}
|
||||
mlog.Print(parsingCommand)
|
||||
if output, err := gproc.ShellExec(ctx, parsingCommand); err != nil {
|
||||
mlog.Print(output)
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
return true
|
||||
})
|
||||
// Custom replacement.
|
||||
//pbFolder := "protobuf"
|
||||
//_, _ = gfile.ScanDirFileFunc(pbFolder, "*.go", true, func(path string) string {
|
||||
// content := gfile.GetContents(path)
|
||||
// content = gstr.ReplaceByArray(content, g.SliceStr{
|
||||
// `gtime "gtime"`, `gtime "github.com/gogf/gf/v2/os/gtime"`,
|
||||
// })
|
||||
// _ = gfile.PutContents(path, content)
|
||||
// utils.GoFmt(path)
|
||||
// return path
|
||||
//})
|
||||
mlog.Print("done!")
|
||||
return
|
||||
}
|
||||
|
||||
@ -1,410 +1,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
import "github.com/gogf/gf/cmd/gf/v2/internal/cmd/genpbentity"
|
||||
|
||||
type (
|
||||
cGenPbEntity struct{}
|
||||
cGenPbEntityInput struct {
|
||||
g.Meta `name:"pbentity" config:"{cGenPbEntityConfig}" brief:"{cGenPbEntityBrief}" eg:"{cGenPbEntityEg}" ad:"{cGenPbEntityAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{cGenPbEntityBriefPath}"`
|
||||
Package string `name:"package" short:"k" brief:"{cGenPbEntityBriefPackage}"`
|
||||
Link string `name:"link" short:"l" brief:"{cGenPbEntityBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{cGenPbEntityBriefTables}"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{cGenPbEntityBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{cGenPbEntityBriefRemovePrefix}"`
|
||||
NameCase string `name:"nameCase" short:"n" brief:"{cGenPbEntityBriefNameCase}" d:"Camel"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{cGenPbEntityBriefJsonCase}" d:"CamelLower"`
|
||||
Option string `name:"option" short:"o" brief:"{cGenPbEntityBriefOption}"`
|
||||
}
|
||||
cGenPbEntityOutput struct{}
|
||||
|
||||
cGenPbEntityInternalInput struct {
|
||||
cGenPbEntityInput
|
||||
TableName string // TableName specifies the table name of the table.
|
||||
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
|
||||
}
|
||||
cGenPbEntity = genpbentity.CGenPbEntity
|
||||
)
|
||||
|
||||
const (
|
||||
cGenPbEntityConfig = `gfcli.gen.pbentity`
|
||||
cGenPbEntityBrief = `generate entity message files in protobuf3 format`
|
||||
cGenPbEntityEg = `
|
||||
gf gen pbentity
|
||||
gf gen pbentity -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
gf gen pbentity -p ./protocol/demos/entity -t user,user_detail,user_login
|
||||
gf gen pbentity -r user_
|
||||
`
|
||||
|
||||
cGenPbEntityAd = `
|
||||
CONFIGURATION SUPPORT
|
||||
Options are also supported by configuration file.
|
||||
It's suggested using configuration file instead of command line arguments making producing.
|
||||
The configuration node name is "gf.gen.pbentity", which also supports multiple databases, for example(config.yaml):
|
||||
gfcli:
|
||||
gen:
|
||||
- pbentity:
|
||||
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
path: "protocol/demos/entity"
|
||||
tables: "order,products"
|
||||
package: "demos"
|
||||
- pbentity:
|
||||
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/primary"
|
||||
path: "protocol/demos/entity"
|
||||
prefix: "primary_"
|
||||
tables: "user, userDetail"
|
||||
package: "demos"
|
||||
option: |
|
||||
option go_package = "protobuf/demos";
|
||||
option java_package = "protobuf/demos";
|
||||
option php_namespace = "protobuf/demos";
|
||||
`
|
||||
cGenPbEntityBriefPath = `directory path for generated files`
|
||||
cGenPbEntityBriefPackage = `package name for all entity proto files`
|
||||
cGenPbEntityBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
|
||||
cGenPbEntityBriefTables = `generate models only for given tables, multiple table names separated with ','`
|
||||
cGenPbEntityBriefPrefix = `add specified prefix for all entity names and entity proto files`
|
||||
cGenPbEntityBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
|
||||
cGenPbEntityBriefOption = `extra protobuf options`
|
||||
cGenPbEntityBriefGroup = `
|
||||
specifying the configuration group name of database for generated ORM instance,
|
||||
it's not necessary and the default value is "default"
|
||||
`
|
||||
|
||||
cGenPbEntityBriefNameCase = `
|
||||
case for message attribute names, default is "Camel":
|
||||
| Case | Example |
|
||||
|---------------- |--------------------|
|
||||
| Camel | AnyKindOfString |
|
||||
| CamelLower | anyKindOfString | default
|
||||
| Snake | any_kind_of_string |
|
||||
| SnakeScreaming | ANY_KIND_OF_STRING |
|
||||
| SnakeFirstUpper | rgb_code_md5 |
|
||||
| Kebab | any-kind-of-string |
|
||||
| KebabScreaming | ANY-KIND-OF-STRING |
|
||||
`
|
||||
|
||||
cGenPbEntityBriefJsonCase = `
|
||||
case for message json tag, cases are the same as "nameCase", default "CamelLower".
|
||||
set it to "none" to ignore json tag generating.
|
||||
`
|
||||
)
|
||||
|
||||
func init() {
|
||||
gtag.Sets(g.MapStrStr{
|
||||
`cGenPbEntityConfig`: cGenPbEntityConfig,
|
||||
`cGenPbEntityBrief`: cGenPbEntityBrief,
|
||||
`cGenPbEntityEg`: cGenPbEntityEg,
|
||||
`cGenPbEntityAd`: cGenPbEntityAd,
|
||||
`cGenPbEntityBriefPath`: cGenPbEntityBriefPath,
|
||||
`cGenPbEntityBriefPackage`: cGenPbEntityBriefPackage,
|
||||
`cGenPbEntityBriefLink`: cGenPbEntityBriefLink,
|
||||
`cGenPbEntityBriefTables`: cGenPbEntityBriefTables,
|
||||
`cGenPbEntityBriefPrefix`: cGenPbEntityBriefPrefix,
|
||||
`cGenPbEntityBriefRemovePrefix`: cGenPbEntityBriefRemovePrefix,
|
||||
`cGenPbEntityBriefGroup`: cGenPbEntityBriefGroup,
|
||||
`cGenPbEntityBriefNameCase`: cGenPbEntityBriefNameCase,
|
||||
`cGenPbEntityBriefJsonCase`: cGenPbEntityBriefJsonCase,
|
||||
`cGenPbEntityBriefOption`: cGenPbEntityBriefOption,
|
||||
})
|
||||
}
|
||||
|
||||
func (c cGenPbEntity) PbEntity(ctx context.Context, in cGenPbEntityInput) (out *cGenPbEntityOutput, err error) {
|
||||
var (
|
||||
config = g.Cfg()
|
||||
)
|
||||
if config.Available(ctx) {
|
||||
v := config.MustGet(ctx, cGenPbEntityConfig)
|
||||
if v.IsSlice() {
|
||||
for i := 0; i < len(v.Interfaces()); i++ {
|
||||
doGenPbEntityForArray(ctx, i, in)
|
||||
}
|
||||
} else {
|
||||
doGenPbEntityForArray(ctx, -1, in)
|
||||
}
|
||||
} else {
|
||||
doGenPbEntityForArray(ctx, -1, in)
|
||||
}
|
||||
mlog.Print("done!")
|
||||
return
|
||||
}
|
||||
|
||||
func doGenPbEntityForArray(ctx context.Context, index int, in cGenPbEntityInput) {
|
||||
var (
|
||||
err error
|
||||
db gdb.DB
|
||||
)
|
||||
if index >= 0 {
|
||||
err = g.Cfg().MustGet(
|
||||
ctx,
|
||||
fmt.Sprintf(`%s.%d`, cGenPbEntityConfig, index),
|
||||
).Scan(&in)
|
||||
if err != nil {
|
||||
mlog.Fatalf(`invalid configuration of "%s": %+v`, cGenPbEntityConfig, err)
|
||||
}
|
||||
}
|
||||
if in.Package == "" {
|
||||
mlog.Fatal("package name should not be empty")
|
||||
}
|
||||
removePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, ",")
|
||||
// It uses user passed database configuration.
|
||||
if in.Link != "" {
|
||||
var (
|
||||
tempGroup = gtime.TimestampNanoStr()
|
||||
match, _ = gregex.MatchString(`([a-z]+):(.+)`, in.Link)
|
||||
)
|
||||
if len(match) == 3 {
|
||||
gdb.AddConfigNode(tempGroup, gdb.ConfigNode{
|
||||
Type: gstr.Trim(match[1]),
|
||||
Link: gstr.Trim(match[2]),
|
||||
})
|
||||
db, _ = gdb.Instance(tempGroup)
|
||||
}
|
||||
} else {
|
||||
db = g.DB()
|
||||
}
|
||||
if db == nil {
|
||||
mlog.Fatal("database initialization failed")
|
||||
}
|
||||
|
||||
tableNames := ([]string)(nil)
|
||||
if in.Tables != "" {
|
||||
tableNames = gstr.SplitAndTrim(in.Tables, ",")
|
||||
} else {
|
||||
tableNames, err = db.Tables(context.TODO())
|
||||
if err != nil {
|
||||
mlog.Fatalf("fetching tables failed: \n %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, tableName := range tableNames {
|
||||
newTableName := tableName
|
||||
for _, v := range removePrefixArray {
|
||||
newTableName = gstr.TrimLeftStr(newTableName, v, 1)
|
||||
}
|
||||
generatePbEntityContentFile(ctx, db, cGenPbEntityInternalInput{
|
||||
cGenPbEntityInput: in,
|
||||
TableName: tableName,
|
||||
NewTableName: newTableName,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// generatePbEntityContentFile generates the protobuf files for given table.
|
||||
func generatePbEntityContentFile(ctx context.Context, db gdb.DB, in cGenPbEntityInternalInput) {
|
||||
fieldMap, err := db.TableFields(ctx, in.TableName)
|
||||
if err != nil {
|
||||
mlog.Fatalf("fetching tables fields failed for table '%s':\n%v", in.TableName, err)
|
||||
}
|
||||
// Change the `newTableName` if `Prefix` is given.
|
||||
newTableName := "Entity_" + in.Prefix + in.NewTableName
|
||||
var (
|
||||
tableNameCamelCase = gstr.CaseCamel(newTableName)
|
||||
tableNameSnakeCase = gstr.CaseSnake(newTableName)
|
||||
entityMessageDefine = generateEntityMessageDefinition(tableNameCamelCase, fieldMap, in)
|
||||
fileName = gstr.Trim(tableNameSnakeCase, "-_.")
|
||||
path = gfile.Join(in.Path, fileName+".proto")
|
||||
)
|
||||
entityContent := gstr.ReplaceByMap(getTplPbEntityContent(""), g.MapStrStr{
|
||||
"{PackageName}": in.Package,
|
||||
"{OptionContent}": in.Option,
|
||||
"{EntityMessage}": entityMessageDefine,
|
||||
})
|
||||
if err := gfile.PutContents(path, strings.TrimSpace(entityContent)); err != nil {
|
||||
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
|
||||
} else {
|
||||
mlog.Print("generated:", path)
|
||||
}
|
||||
}
|
||||
|
||||
// generateEntityMessageDefinition generates and returns the message definition for specified table.
|
||||
func generateEntityMessageDefinition(entityName string, fieldMap map[string]*gdb.TableField, in cGenPbEntityInternalInput) string {
|
||||
var (
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
array = make([][]string, len(fieldMap))
|
||||
names = sortFieldKeyForPbEntity(fieldMap)
|
||||
)
|
||||
for index, name := range names {
|
||||
array[index] = generateMessageFieldForPbEntity(index+1, fieldMap[name], in)
|
||||
}
|
||||
tw := tablewriter.NewWriter(buffer)
|
||||
tw.SetBorder(false)
|
||||
tw.SetRowLine(false)
|
||||
tw.SetAutoWrapText(false)
|
||||
tw.SetColumnSeparator("")
|
||||
tw.AppendBulk(array)
|
||||
tw.Render()
|
||||
stContent := buffer.String()
|
||||
// Let's do this hack of table writer for indent!
|
||||
stContent = gstr.Replace(stContent, " #", "")
|
||||
buffer.Reset()
|
||||
buffer.WriteString(fmt.Sprintf("message %s {\n", entityName))
|
||||
buffer.WriteString(stContent)
|
||||
buffer.WriteString("}")
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// generateMessageFieldForPbEntity generates and returns the message definition for specified field.
|
||||
func generateMessageFieldForPbEntity(index int, field *gdb.TableField, in cGenPbEntityInternalInput) []string {
|
||||
var (
|
||||
typeName string
|
||||
comment string
|
||||
jsonTagStr string
|
||||
)
|
||||
t, _ := gregex.ReplaceString(`\(.+\)`, "", field.Type)
|
||||
t = gstr.Split(gstr.Trim(t), " ")[0]
|
||||
t = gstr.ToLower(t)
|
||||
switch t {
|
||||
case "binary", "varbinary", "blob", "tinyblob", "mediumblob", "longblob":
|
||||
typeName = "bytes"
|
||||
|
||||
case "bit", "int", "tinyint", "small_int", "smallint", "medium_int", "mediumint", "serial":
|
||||
if gstr.ContainsI(field.Type, "unsigned") {
|
||||
typeName = "uint32"
|
||||
} else {
|
||||
typeName = "int32"
|
||||
}
|
||||
|
||||
case "int8", "big_int", "bigint", "bigserial":
|
||||
if gstr.ContainsI(field.Type, "unsigned") {
|
||||
typeName = "uint64"
|
||||
} else {
|
||||
typeName = "int64"
|
||||
}
|
||||
|
||||
case "real":
|
||||
typeName = "float"
|
||||
|
||||
case "float", "double", "decimal", "smallmoney":
|
||||
typeName = "double"
|
||||
|
||||
case "bool":
|
||||
typeName = "bool"
|
||||
|
||||
case "datetime", "timestamp", "date", "time":
|
||||
typeName = "int64"
|
||||
|
||||
default:
|
||||
// Auto detecting type.
|
||||
switch {
|
||||
case strings.Contains(t, "int"):
|
||||
typeName = "int"
|
||||
case strings.Contains(t, "text") || strings.Contains(t, "char"):
|
||||
typeName = "string"
|
||||
case strings.Contains(t, "float") || strings.Contains(t, "double"):
|
||||
typeName = "double"
|
||||
case strings.Contains(t, "bool"):
|
||||
typeName = "bool"
|
||||
case strings.Contains(t, "binary") || strings.Contains(t, "blob"):
|
||||
typeName = "bytes"
|
||||
case strings.Contains(t, "date") || strings.Contains(t, "time"):
|
||||
typeName = "int64"
|
||||
default:
|
||||
typeName = "string"
|
||||
}
|
||||
}
|
||||
comment = gstr.ReplaceByArray(field.Comment, g.SliceStr{
|
||||
"\n", " ",
|
||||
"\r", " ",
|
||||
})
|
||||
comment = gstr.Trim(comment)
|
||||
comment = gstr.Replace(comment, `\n`, " ")
|
||||
comment, _ = gregex.ReplaceString(`\s{2,}`, ` `, comment)
|
||||
if jsonTagName := formatCase(field.Name, in.JsonCase); jsonTagName != "" {
|
||||
jsonTagStr = fmt.Sprintf(`[(gogoproto.jsontag) = "%s"]`, jsonTagName)
|
||||
// beautiful indent.
|
||||
if index < 10 {
|
||||
// 3 spaces
|
||||
jsonTagStr = " " + jsonTagStr
|
||||
} else if index < 100 {
|
||||
// 2 spaces
|
||||
jsonTagStr = " " + jsonTagStr
|
||||
} else {
|
||||
// 1 spaces
|
||||
jsonTagStr = " " + jsonTagStr
|
||||
}
|
||||
}
|
||||
return []string{
|
||||
" #" + typeName,
|
||||
" #" + formatCase(field.Name, in.NameCase),
|
||||
" #= " + gconv.String(index) + jsonTagStr + ";",
|
||||
" #" + fmt.Sprintf(`// %s`, comment),
|
||||
}
|
||||
}
|
||||
|
||||
func getTplPbEntityContent(tplEntityPath string) string {
|
||||
if tplEntityPath != "" {
|
||||
return gfile.GetContents(tplEntityPath)
|
||||
}
|
||||
return consts.TemplatePbEntityMessageContent
|
||||
}
|
||||
|
||||
// formatCase call gstr.Case* function to convert the s to specified case.
|
||||
func formatCase(str, caseStr string) string {
|
||||
switch gstr.ToLower(caseStr) {
|
||||
case gstr.ToLower("Camel"):
|
||||
return gstr.CaseCamel(str)
|
||||
|
||||
case gstr.ToLower("CamelLower"):
|
||||
return gstr.CaseCamelLower(str)
|
||||
|
||||
case gstr.ToLower("Kebab"):
|
||||
return gstr.CaseKebab(str)
|
||||
|
||||
case gstr.ToLower("KebabScreaming"):
|
||||
return gstr.CaseKebabScreaming(str)
|
||||
|
||||
case gstr.ToLower("Snake"):
|
||||
return gstr.CaseSnake(str)
|
||||
|
||||
case gstr.ToLower("SnakeFirstUpper"):
|
||||
return gstr.CaseSnakeFirstUpper(str)
|
||||
|
||||
case gstr.ToLower("SnakeScreaming"):
|
||||
return gstr.CaseSnakeScreaming(str)
|
||||
|
||||
case "none":
|
||||
return ""
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func sortFieldKeyForPbEntity(fieldMap map[string]*gdb.TableField) []string {
|
||||
names := make(map[int]string)
|
||||
for _, field := range fieldMap {
|
||||
names[field.Index] = field.Name
|
||||
}
|
||||
var (
|
||||
result = make([]string, len(names))
|
||||
i = 0
|
||||
j = 0
|
||||
)
|
||||
for {
|
||||
if len(names) == 0 {
|
||||
break
|
||||
}
|
||||
if val, ok := names[i]; ok {
|
||||
result[j] = val
|
||||
j++
|
||||
delete(names, i)
|
||||
}
|
||||
i++
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@ -5,14 +5,15 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/os/gres"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -52,6 +53,7 @@ type cInitInput struct {
|
||||
Mono bool `name:"mono" short:"m" brief:"initialize a mono-repo instead a single-repo" orphan:"true"`
|
||||
Update bool `name:"update" short:"u" brief:"update to the latest goframe version" orphan:"true"`
|
||||
}
|
||||
|
||||
type cInitOutput struct{}
|
||||
|
||||
func (c cInit) Index(ctx context.Context, in cInitInput) (out *cInitOutput, err error) {
|
||||
|
||||
@ -3,8 +3,9 @@ package cmd
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/service"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/service"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -18,6 +19,7 @@ type cInstall struct {
|
||||
type cInstallInput struct {
|
||||
g.Meta `name:"install"`
|
||||
}
|
||||
|
||||
type cInstallOutput struct{}
|
||||
|
||||
func (c cInstall) Index(ctx context.Context, in cInstallInput) (out *cInstallOutput, err error) {
|
||||
|
||||
@ -4,13 +4,14 @@ import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gres"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -37,29 +38,33 @@ gf pack /var/www/public packed/data.go -n=packed
|
||||
destination file path for packed file. if extension of the filename is ".go" and "-n" option is given,
|
||||
it enables packing SRC to go file, or else it packs SRC into a binary file.
|
||||
`
|
||||
cPackNameBrief = `package name for output go file, it's set as its directory name if no name passed`
|
||||
cPackPrefixBrief = `prefix for each file packed into the resource file`
|
||||
cPackNameBrief = `package name for output go file, it's set as its directory name if no name passed`
|
||||
cPackPrefixBrief = `prefix for each file packed into the resource file`
|
||||
cPackKeepPathBrief = `keep the source path from system to resource file, usually for relative path`
|
||||
)
|
||||
|
||||
func init() {
|
||||
gtag.Sets(g.MapStrStr{
|
||||
`cPackUsage`: cPackUsage,
|
||||
`cPackBrief`: cPackBrief,
|
||||
`cPackEg`: cPackEg,
|
||||
`cPackSrcBrief`: cPackSrcBrief,
|
||||
`cPackDstBrief`: cPackDstBrief,
|
||||
`cPackNameBrief`: cPackNameBrief,
|
||||
`cPackPrefixBrief`: cPackPrefixBrief,
|
||||
`cPackUsage`: cPackUsage,
|
||||
`cPackBrief`: cPackBrief,
|
||||
`cPackEg`: cPackEg,
|
||||
`cPackSrcBrief`: cPackSrcBrief,
|
||||
`cPackDstBrief`: cPackDstBrief,
|
||||
`cPackNameBrief`: cPackNameBrief,
|
||||
`cPackPrefixBrief`: cPackPrefixBrief,
|
||||
`cPackKeepPathBrief`: cPackKeepPathBrief,
|
||||
})
|
||||
}
|
||||
|
||||
type cPackInput struct {
|
||||
g.Meta `name:"pack"`
|
||||
Src string `name:"SRC" arg:"true" v:"required" brief:"{cPackSrcBrief}"`
|
||||
Dst string `name:"DST" arg:"true" v:"required" brief:"{cPackDstBrief}"`
|
||||
Name string `name:"name" short:"n" brief:"{cPackNameBrief}"`
|
||||
Prefix string `name:"prefix" short:"p" brief:"{cPackPrefixBrief}"`
|
||||
g.Meta `name:"pack"`
|
||||
Src string `name:"SRC" arg:"true" v:"required" brief:"{cPackSrcBrief}"`
|
||||
Dst string `name:"DST" arg:"true" v:"required" brief:"{cPackDstBrief}"`
|
||||
Name string `name:"name" short:"n" brief:"{cPackNameBrief}"`
|
||||
Prefix string `name:"prefix" short:"p" brief:"{cPackPrefixBrief}"`
|
||||
KeepPath bool `name:"keepPath" short:"k" brief:"{cPackKeepPathBrief}" orphan:"true"`
|
||||
}
|
||||
|
||||
type cPackOutput struct{}
|
||||
|
||||
func (c cPack) Index(ctx context.Context, in cPackInput) (out *cPackOutput, err error) {
|
||||
@ -75,12 +80,16 @@ func (c cPack) Index(ctx context.Context, in cPackInput) (out *cPackOutput, err
|
||||
if in.Name == "" && gfile.ExtName(in.Dst) == "go" {
|
||||
in.Name = gfile.Basename(gfile.Dir(in.Dst))
|
||||
}
|
||||
var option = gres.Option{
|
||||
Prefix: in.Prefix,
|
||||
KeepPath: in.KeepPath,
|
||||
}
|
||||
if in.Name != "" {
|
||||
if err = gres.PackToGoFile(in.Src, in.Dst, in.Name, in.Prefix); err != nil {
|
||||
if err = gres.PackToGoFileWithOption(in.Src, in.Dst, in.Name, option); err != nil {
|
||||
mlog.Fatalf("pack failed: %v", err)
|
||||
}
|
||||
} else {
|
||||
if err = gres.PackToFile(in.Src, in.Dst, in.Prefix); err != nil {
|
||||
if err = gres.PackToFileWithOption(in.Src, in.Dst, option); err != nil {
|
||||
mlog.Fatalf("pack failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,8 +4,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/container/gtype"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
@ -14,6 +14,8 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/os/gtimer"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -153,7 +155,7 @@ func (app *cRunApp) Run(ctx context.Context) {
|
||||
if runtime.GOOS == "windows" {
|
||||
// Special handling for windows platform.
|
||||
// DO NOT USE "cmd /c" command.
|
||||
process = gproc.NewProcess(runCommand, nil)
|
||||
process = gproc.NewProcess(outputPath, strings.Fields(app.Args))
|
||||
} else {
|
||||
process = gproc.NewProcessCmd(runCommand, nil)
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@ package cmd
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@ -11,6 +10,8 @@ import (
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
207
cmd/gf/internal/cmd/cmd_up.go
Normal file
207
cmd/gf/internal/cmd/cmd_up.go
Normal file
@ -0,0 +1,207 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
"github.com/gogf/gf/v2/container/gset"
|
||||
"runtime"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
)
|
||||
|
||||
var (
|
||||
Up = cUp{}
|
||||
)
|
||||
|
||||
type cUp struct {
|
||||
g.Meta `name:"up" brief:"upgrade GoFrame version/tool to latest one in current project" eg:"{cUpEg}" `
|
||||
}
|
||||
|
||||
const (
|
||||
gfPackage = `github.com/gogf/gf/`
|
||||
cUpEg = `
|
||||
gf up
|
||||
gf up -a
|
||||
gf up -c
|
||||
gf up -cf
|
||||
`
|
||||
)
|
||||
|
||||
func init() {
|
||||
gtag.Sets(g.MapStrStr{
|
||||
`cUpEg`: cUpEg,
|
||||
})
|
||||
}
|
||||
|
||||
type cUpInput struct {
|
||||
g.Meta `name:"up" config:"gfcli.up"`
|
||||
All bool `name:"all" short:"a" brief:"upgrade both version and cli, auto fix codes" orphan:"true"`
|
||||
Cli bool `name:"cli" short:"c" brief:"also upgrade CLI tool" orphan:"true"`
|
||||
Fix bool `name:"fix" short:"f" brief:"auto fix codes(it only make sense if cli is to be upgraded)" orphan:"true"`
|
||||
}
|
||||
|
||||
type cUpOutput struct{}
|
||||
|
||||
func (c cUp) Index(ctx context.Context, in cUpInput) (out *cUpOutput, err error) {
|
||||
defer func() {
|
||||
if err == nil {
|
||||
mlog.Print()
|
||||
mlog.Print(`👏congratulations! you've upgraded to the latest version of GoFrame! enjoy it!👏`)
|
||||
mlog.Print()
|
||||
}
|
||||
}()
|
||||
|
||||
var doUpgradeVersionOut *doUpgradeVersionOutput
|
||||
if in.All {
|
||||
in.Cli = true
|
||||
in.Fix = true
|
||||
}
|
||||
if doUpgradeVersionOut, err = c.doUpgradeVersion(ctx, in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if in.Cli {
|
||||
if err = c.doUpgradeCLI(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if in.Cli && in.Fix {
|
||||
if doUpgradeVersionOut != nil && len(doUpgradeVersionOut.Items) > 0 {
|
||||
upgradedPathSet := gset.NewStrSet()
|
||||
for _, item := range doUpgradeVersionOut.Items {
|
||||
if !upgradedPathSet.AddIfNotExist(item.DirPath) {
|
||||
continue
|
||||
}
|
||||
if err = c.doAutoFixing(ctx, item.DirPath, item.Version); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type doUpgradeVersionOutput struct {
|
||||
Items []doUpgradeVersionOutputItem
|
||||
}
|
||||
|
||||
type doUpgradeVersionOutputItem struct {
|
||||
DirPath string
|
||||
Version string
|
||||
}
|
||||
|
||||
func (c cUp) doUpgradeVersion(ctx context.Context, in cUpInput) (out *doUpgradeVersionOutput, err error) {
|
||||
mlog.Print(`start upgrading version...`)
|
||||
out = &doUpgradeVersionOutput{
|
||||
Items: make([]doUpgradeVersionOutputItem, 0),
|
||||
}
|
||||
type Package struct {
|
||||
Name string
|
||||
Version string
|
||||
}
|
||||
|
||||
var (
|
||||
temp string
|
||||
dirPath = gfile.Pwd()
|
||||
goModPath = gfile.Join(dirPath, "go.mod")
|
||||
)
|
||||
// It recursively upgrades the go.mod from sub folder to its parent folders.
|
||||
for {
|
||||
if gfile.Exists(goModPath) {
|
||||
var packages []Package
|
||||
err = gfile.ReadLines(goModPath, func(line string) error {
|
||||
line = gstr.Trim(line)
|
||||
if gstr.HasPrefix(line, gfPackage) {
|
||||
array := gstr.SplitAndTrim(line, " ")
|
||||
packages = append(packages, Package{
|
||||
Name: array[0],
|
||||
Version: array[1],
|
||||
})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, pkg := range packages {
|
||||
mlog.Printf(`upgrading "%s" from "%s" to "latest"`, pkg.Name, pkg.Version)
|
||||
// go get -u
|
||||
command := fmt.Sprintf(`cd %s && go get -u %s@latest`, dirPath, pkg.Name)
|
||||
if err = gproc.ShellRun(ctx, command); err != nil {
|
||||
return
|
||||
}
|
||||
// go mod tidy
|
||||
if err = utils.GoModTidy(ctx, dirPath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out.Items = append(out.Items, doUpgradeVersionOutputItem{
|
||||
DirPath: dirPath,
|
||||
Version: pkg.Version,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
temp = gfile.Dir(dirPath)
|
||||
if temp == "" || temp == dirPath {
|
||||
return
|
||||
}
|
||||
dirPath = temp
|
||||
goModPath = gfile.Join(dirPath, "go.mod")
|
||||
}
|
||||
}
|
||||
|
||||
// doUpgradeCLI downloads the new version binary with process.
|
||||
func (c cUp) doUpgradeCLI(ctx context.Context) (err error) {
|
||||
mlog.Print(`start upgrading cli...`)
|
||||
var (
|
||||
downloadUrl = fmt.Sprintf(
|
||||
`https://github.com/gogf/gf/releases/latest/download/gf_%s_%s`,
|
||||
runtime.GOOS, runtime.GOARCH,
|
||||
)
|
||||
localSaveFilePath = gfile.SelfPath() + "~"
|
||||
)
|
||||
mlog.Printf(`start downloading "%s" to "%s", it may take some time`, downloadUrl, localSaveFilePath)
|
||||
err = utils.HTTPDownloadFileWithPercent(downloadUrl, localSaveFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
mlog.Printf(`new version cli binary is successfully installed to "%s"`, gfile.SelfPath())
|
||||
mlog.Printf(`remove temporary buffer file "%s"`, localSaveFilePath)
|
||||
_ = gfile.Remove(localSaveFilePath)
|
||||
}()
|
||||
|
||||
// It fails if file not exist or its size is less than 1MB.
|
||||
if !gfile.Exists(localSaveFilePath) || gfile.Size(localSaveFilePath) < 1024*1024 {
|
||||
mlog.Fatalf(`download "%s" to "%s" failed`, downloadUrl, localSaveFilePath)
|
||||
}
|
||||
|
||||
// It replaces self binary with new version cli binary.
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
if err := gfile.Rename(localSaveFilePath, gfile.SelfPath()); err != nil {
|
||||
mlog.Fatalf(`install failed: %s`, err.Error())
|
||||
}
|
||||
|
||||
default:
|
||||
if err := gfile.PutBytes(gfile.SelfPath(), gfile.GetBytes(localSaveFilePath)); err != nil {
|
||||
mlog.Fatalf(`install failed: %s`, err.Error())
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c cUp) doAutoFixing(ctx context.Context, dirPath string, version string) (err error) {
|
||||
mlog.Printf(`auto fixing directory path "%s" from version "%s" ...`, dirPath, version)
|
||||
command := fmt.Sprintf(`gf fix -p %s`, dirPath)
|
||||
_ = gproc.ShellRun(ctx, command)
|
||||
return
|
||||
}
|
||||
@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@ -12,6 +11,8 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -25,6 +26,7 @@ type cVersion struct {
|
||||
type cVersionInput struct {
|
||||
g.Meta `name:"version"`
|
||||
}
|
||||
|
||||
type cVersionOutput struct{}
|
||||
|
||||
func (c cVersion) Index(ctx context.Context, in cVersionInput) (*cVersionOutput, error) {
|
||||
|
||||
@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@ -14,6 +13,8 @@ import (
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -215,6 +216,7 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
|
||||
}
|
||||
removePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, ",")
|
||||
if in.ImportPrefix == "" {
|
||||
mlog.Debug(`import prefix is empty, trying calculating the import package path using go.mod`)
|
||||
if !gfile.Exists("go.mod") {
|
||||
mlog.Fatal("go.mod does not exist in current working directory")
|
||||
}
|
||||
|
||||
@ -3,18 +3,19 @@ package gendao
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
)
|
||||
|
||||
func doClear(ctx context.Context, dirPath string) {
|
||||
func doClear(ctx context.Context, dirPath string, force bool) {
|
||||
files, err := gfile.ScanDirFile(dirPath, "*.go", true)
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
for _, file := range files {
|
||||
if utils.IsFileDoNotEdit(file) {
|
||||
if force || utils.IsFileDoNotEdit(file) {
|
||||
if err = gfile.Remove(file); err != nil {
|
||||
mlog.Print(err)
|
||||
}
|
||||
|
||||
@ -6,15 +6,17 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
)
|
||||
|
||||
func generateDao(ctx context.Context, in CGenDaoInternalInput) {
|
||||
@ -23,7 +25,7 @@ func generateDao(ctx context.Context, in CGenDaoInternalInput) {
|
||||
dirPathDaoInternal = gfile.Join(dirPathDao, "internal")
|
||||
)
|
||||
if in.Clear {
|
||||
doClear(ctx, dirPathDao)
|
||||
doClear(ctx, dirPathDao, true)
|
||||
}
|
||||
for i := 0; i < len(in.TableNames); i++ {
|
||||
generateDaoSingle(ctx, generateDaoSingleInput{
|
||||
|
||||
@ -5,19 +5,20 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
)
|
||||
|
||||
func generateDo(ctx context.Context, in CGenDaoInternalInput) {
|
||||
var dirPathDo = gfile.Join(in.Path, in.DoPath)
|
||||
if in.Clear {
|
||||
doClear(ctx, dirPathDo)
|
||||
doClear(ctx, dirPathDo, false)
|
||||
}
|
||||
in.NoJsonTag = true
|
||||
in.DescriptionTag = false
|
||||
|
||||
@ -4,18 +4,19 @@ import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
)
|
||||
|
||||
func generateEntity(ctx context.Context, in CGenDaoInternalInput) {
|
||||
var dirPathEntity = gfile.Join(in.Path, in.EntityPath)
|
||||
if in.Clear {
|
||||
doClear(ctx, dirPathEntity)
|
||||
doClear(ctx, dirPathEntity, false)
|
||||
}
|
||||
// Model content.
|
||||
for i, tableName := range in.TableNames {
|
||||
|
||||
122
cmd/gf/internal/cmd/genpb/genpb.go
Normal file
122
cmd/gf/internal/cmd/genpb/genpb.go
Normal file
@ -0,0 +1,122 @@
|
||||
package genpb
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
)
|
||||
|
||||
type (
|
||||
CGenPb struct{}
|
||||
CGenPbInput struct {
|
||||
g.Meta `name:"pb" config:"{CGenPbConfig}" brief:"{CGenPbBrief}" eg:"{CGenPbEg}"`
|
||||
Path string `name:"path" short:"p" dc:"protobuf file folder path" d:"manifest/protobuf"`
|
||||
OutputApi string `name:"api" short:"a" dc:"output folder path storing generated go files of api" d:"api"`
|
||||
OutputCtrl string `name:"ctrl" short:"c" dc:"output folder path storing generated go files of controller" d:"internal/controller"`
|
||||
}
|
||||
CGenPbOutput struct{}
|
||||
)
|
||||
|
||||
const (
|
||||
CGenPbConfig = `gfcli.gen.pb`
|
||||
CGenPbBrief = `parse proto files and generate protobuf go files`
|
||||
CGenPbEg = `
|
||||
gf gen pb
|
||||
gf gen pb -p . -a . -p .
|
||||
`
|
||||
)
|
||||
|
||||
func init() {
|
||||
gtag.Sets(g.MapStrStr{
|
||||
`CGenPbEg`: CGenPbEg,
|
||||
`CGenPbBrief`: CGenPbBrief,
|
||||
`CGenPbConfig`: CGenPbConfig,
|
||||
})
|
||||
}
|
||||
|
||||
func (c CGenPb) Pb(ctx context.Context, in CGenPbInput) (out *CGenPbOutput, err error) {
|
||||
// Necessary check.
|
||||
protoc := gproc.SearchBinary("protoc")
|
||||
if protoc == "" {
|
||||
mlog.Fatalf(`command "protoc" not found in your environment, please install protoc first: https://grpc.io/docs/languages/go/quickstart/`)
|
||||
}
|
||||
|
||||
// protocol fold checks.
|
||||
var (
|
||||
protoPath = gfile.RealPath(in.Path)
|
||||
isParsingPWD bool
|
||||
)
|
||||
if protoPath == "" {
|
||||
// Use current working directory as protoPath if there are proto files under.
|
||||
currentPath := gfile.Pwd()
|
||||
currentFiles, _ := gfile.ScanDirFile(currentPath, "*.proto")
|
||||
if len(currentFiles) > 0 {
|
||||
protoPath = currentPath
|
||||
isParsingPWD = true
|
||||
} else {
|
||||
mlog.Fatalf(`proto files folder "%s" does not exist`, in.Path)
|
||||
}
|
||||
}
|
||||
// output path checks.
|
||||
outputApiPath := gfile.RealPath(in.OutputApi)
|
||||
if outputApiPath == "" {
|
||||
if isParsingPWD {
|
||||
outputApiPath = protoPath
|
||||
} else {
|
||||
mlog.Fatalf(`output api folder "%s" does not exist`, in.OutputApi)
|
||||
}
|
||||
}
|
||||
outputCtrlPath := gfile.RealPath(in.OutputCtrl)
|
||||
if outputCtrlPath == "" {
|
||||
if isParsingPWD {
|
||||
outputCtrlPath = ""
|
||||
} else {
|
||||
mlog.Fatalf(`output controller folder "%s" does not exist`, in.OutputCtrl)
|
||||
}
|
||||
}
|
||||
|
||||
// folder scanning.
|
||||
files, err := gfile.ScanDirFile(protoPath, "*.proto", true)
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
if len(files) == 0 {
|
||||
mlog.Fatalf(`no proto files found in folder "%s"`, in.Path)
|
||||
}
|
||||
|
||||
if err = gfile.Chdir(protoPath); err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
for _, file := range files {
|
||||
var command = gproc.NewProcess(protoc, nil)
|
||||
command.Args = append(command.Args, "--proto_path="+gfile.Pwd())
|
||||
command.Args = append(command.Args, "--go_out=paths=source_relative:"+outputApiPath)
|
||||
command.Args = append(command.Args, "--go-grpc_out=paths=source_relative:"+outputApiPath)
|
||||
command.Args = append(command.Args, file)
|
||||
mlog.Print(command.String())
|
||||
if err = command.Run(ctx); err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
}
|
||||
// Generate struct tag according comment rules.
|
||||
err = c.generateStructTag(ctx, generateStructTagInput{OutputApiPath: outputApiPath})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Generate controllers according comment rules.
|
||||
if outputCtrlPath != "" {
|
||||
err = c.generateController(ctx, generateControllerInput{
|
||||
OutputApiPath: outputApiPath,
|
||||
OutputCtrlPath: outputCtrlPath,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
mlog.Print("done!")
|
||||
return
|
||||
}
|
||||
189
cmd/gf/internal/cmd/genpb/genpb_controller.go
Normal file
189
cmd/gf/internal/cmd/genpb/genpb_controller.go
Normal file
@ -0,0 +1,189 @@
|
||||
package genpb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
type generateControllerInput struct {
|
||||
OutputApiPath string
|
||||
OutputCtrlPath string
|
||||
}
|
||||
|
||||
type generateCtrl struct {
|
||||
Name string
|
||||
Package string
|
||||
Version string
|
||||
Methods []generateCtrlMethod
|
||||
}
|
||||
|
||||
type generateCtrlMethod struct {
|
||||
Name string
|
||||
Definition string
|
||||
}
|
||||
|
||||
const (
|
||||
controllerTemplate = `
|
||||
package {Package}
|
||||
|
||||
type Controller struct {
|
||||
{Version}.Unimplemented{Name}Server
|
||||
}
|
||||
|
||||
func Register(s *grpcx.GrpcServer) {
|
||||
{Version}.Register{Name}Server(s.Server, &Controller{})
|
||||
}
|
||||
`
|
||||
controllerMethodTemplate = `
|
||||
func (*Controller) {Definition} {
|
||||
return nil, gerror.NewCode(gcode.CodeNotImplemented)
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
func (c CGenPb) generateController(ctx context.Context, in generateControllerInput) (err error) {
|
||||
files, err := gfile.ScanDirFile(in.OutputApiPath, "*_grpc.pb.go", true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var controllers []generateCtrl
|
||||
for _, file := range files {
|
||||
fileControllers, err := c.parseControllers(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
controllers = append(controllers, fileControllers...)
|
||||
}
|
||||
if len(controllers) == 0 {
|
||||
return nil
|
||||
}
|
||||
// Generate controller files.
|
||||
err = c.doGenerateControllers(in, controllers)
|
||||
return
|
||||
}
|
||||
|
||||
func (c CGenPb) parseControllers(filePath string) ([]generateCtrl, error) {
|
||||
var (
|
||||
controllers []generateCtrl
|
||||
content = gfile.GetContents(filePath)
|
||||
)
|
||||
_, err := gregex.ReplaceStringFuncMatch(
|
||||
`type (\w+)Server interface {([\s\S]+?)}`,
|
||||
content,
|
||||
func(match []string) string {
|
||||
ctrl := generateCtrl{
|
||||
Name: match[1],
|
||||
Package: gfile.Basename(gfile.Dir(gfile.Dir(filePath))),
|
||||
Version: gfile.Basename(gfile.Dir(filePath)),
|
||||
Methods: make([]generateCtrlMethod, 0),
|
||||
}
|
||||
lines := gstr.Split(match[2], "\n")
|
||||
for _, line := range lines {
|
||||
line = gstr.Trim(line)
|
||||
if line == "" || !gstr.IsLetterUpper(line[0]) {
|
||||
continue
|
||||
}
|
||||
// Comment.
|
||||
if gregex.IsMatchString(`^//.+`, line) {
|
||||
continue
|
||||
}
|
||||
line, _ = gregex.ReplaceStringFuncMatch(
|
||||
`^(\w+)\(context\.Context, \*(\w+)\) \(\*(\w+), error\)$`,
|
||||
line,
|
||||
func(match []string) string {
|
||||
return fmt.Sprintf(
|
||||
`%s(ctx context.Context, req *%s.%s) (res *%s.%s, err error)`,
|
||||
match[1], ctrl.Version, match[2], ctrl.Version, match[3],
|
||||
)
|
||||
},
|
||||
)
|
||||
ctrl.Methods = append(ctrl.Methods, generateCtrlMethod{
|
||||
Name: gstr.Split(line, "(")[0],
|
||||
Definition: line,
|
||||
})
|
||||
}
|
||||
if len(ctrl.Methods) > 0 {
|
||||
controllers = append(controllers, ctrl)
|
||||
}
|
||||
return match[0]
|
||||
},
|
||||
)
|
||||
return controllers, err
|
||||
}
|
||||
|
||||
func (c CGenPb) doGenerateControllers(in generateControllerInput, controllers []generateCtrl) (err error) {
|
||||
for _, controller := range controllers {
|
||||
err = c.doGenerateController(in, controller)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = utils.ReplaceGeneratedContentGFV2(in.OutputCtrlPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c CGenPb) doGenerateController(in generateControllerInput, controller generateCtrl) (err error) {
|
||||
var (
|
||||
folderPath = gfile.Join(in.OutputCtrlPath, controller.Package)
|
||||
filePath = gfile.Join(folderPath, controller.Package+".go")
|
||||
isDirty bool
|
||||
)
|
||||
if !gfile.Exists(folderPath) {
|
||||
if err = gfile.Mkdir(folderPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !gfile.Exists(filePath) {
|
||||
templateContent := gstr.ReplaceByMap(controllerTemplate, g.MapStrStr{
|
||||
"{Name}": controller.Name,
|
||||
"{Version}": controller.Version,
|
||||
"{Package}": controller.Package,
|
||||
})
|
||||
if err = gfile.PutContents(filePath, templateContent); err != nil {
|
||||
return err
|
||||
}
|
||||
isDirty = true
|
||||
}
|
||||
// Exist controller content.
|
||||
var ctrlContent string
|
||||
files, err := gfile.ScanDirFile(folderPath, "*.go", false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, file := range files {
|
||||
if ctrlContent != "" {
|
||||
ctrlContent += "\n"
|
||||
}
|
||||
ctrlContent += gfile.GetContents(file)
|
||||
}
|
||||
// Generate method content.
|
||||
var generatedContent string
|
||||
for _, method := range controller.Methods {
|
||||
if gstr.Contains(ctrlContent, fmt.Sprintf(`%s(`, method.Name)) {
|
||||
continue
|
||||
}
|
||||
if generatedContent != "" {
|
||||
generatedContent += "\n"
|
||||
}
|
||||
generatedContent += gstr.ReplaceByMap(controllerMethodTemplate, g.MapStrStr{
|
||||
"{Definition}": method.Definition,
|
||||
})
|
||||
}
|
||||
if generatedContent != "" {
|
||||
err = gfile.PutContentsAppend(filePath, generatedContent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
isDirty = true
|
||||
}
|
||||
if isDirty {
|
||||
utils.GoFmt(filePath)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
107
cmd/gf/internal/cmd/genpb/genpb_tag.go
Normal file
107
cmd/gf/internal/cmd/genpb/genpb_tag.go
Normal file
@ -0,0 +1,107 @@
|
||||
package genpb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
type generateStructTagInput struct {
|
||||
OutputApiPath string
|
||||
}
|
||||
|
||||
func (c CGenPb) generateStructTag(ctx context.Context, in generateStructTagInput) (err error) {
|
||||
files, err := gfile.ScanDirFile(in.OutputApiPath, "*.pb.go", true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var content string
|
||||
for _, file := range files {
|
||||
content = gfile.GetContents(file)
|
||||
content, err = c.doTagReplacement(ctx, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = gfile.PutContents(file, content); err != nil {
|
||||
return err
|
||||
}
|
||||
utils.GoFmt(file)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c CGenPb) doTagReplacement(ctx context.Context, content string) (string, error) {
|
||||
content, err := gregex.ReplaceStringFuncMatch(`type (\w+) struct {([\s\S]+?)}`, content, func(match []string) string {
|
||||
var (
|
||||
topCommentMatch []string
|
||||
tailCommentMatch []string
|
||||
lines = gstr.Split(match[2], "\n")
|
||||
lineTagMap = gmap.NewListMap()
|
||||
)
|
||||
for index, line := range lines {
|
||||
line = gstr.Trim(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
// Top comment.
|
||||
topCommentMatch, _ = gregex.MatchString(`^/[/|\*](.+)`, line)
|
||||
if len(topCommentMatch) > 1 {
|
||||
c.tagCommentIntoListMap(gstr.Trim(topCommentMatch[1]), lineTagMap)
|
||||
continue
|
||||
}
|
||||
// Tail comment.
|
||||
tailCommentMatch, _ = gregex.MatchString(".+?`.+?`.+?//(.+)", line)
|
||||
if len(tailCommentMatch) > 1 {
|
||||
c.tagCommentIntoListMap(gstr.Trim(tailCommentMatch[1]), lineTagMap)
|
||||
}
|
||||
// Tag injection.
|
||||
if !lineTagMap.IsEmpty() {
|
||||
tagContent := c.listMapToStructTag(lineTagMap)
|
||||
lineTagMap.Clear()
|
||||
line, _ = gregex.ReplaceString("`(.+)`", fmt.Sprintf("`$1 %s`", tagContent), line)
|
||||
}
|
||||
lines[index] = line
|
||||
}
|
||||
match[2] = gstr.Join(lines, "\n")
|
||||
return fmt.Sprintf("type %s struct {%s}", match[1], match[2])
|
||||
})
|
||||
return content, err
|
||||
}
|
||||
|
||||
func (c CGenPb) tagCommentIntoListMap(comment string, lineTagMap *gmap.ListMap) {
|
||||
tagCommentMatch, _ := gregex.MatchString(`^(\w+):(.+)`, comment)
|
||||
if len(tagCommentMatch) > 1 {
|
||||
var (
|
||||
tagName = gstr.Trim(tagCommentMatch[1])
|
||||
tagContent = gstr.Trim(tagCommentMatch[2])
|
||||
)
|
||||
lineTagMap.Set(tagName, lineTagMap.GetVar(tagName).String()+tagContent)
|
||||
} else {
|
||||
var (
|
||||
tagName = "dc"
|
||||
tagContent = comment
|
||||
)
|
||||
lineTagMap.Set(tagName, lineTagMap.GetVar(tagName).String()+tagContent)
|
||||
}
|
||||
}
|
||||
|
||||
func (c CGenPb) listMapToStructTag(lineTagMap *gmap.ListMap) string {
|
||||
var tag string
|
||||
lineTagMap.Iterator(func(key, value interface{}) bool {
|
||||
if tag != "" {
|
||||
tag += " "
|
||||
}
|
||||
tag += fmt.Sprintf(
|
||||
`%s:"%s"`,
|
||||
key, gstr.Replace(gconv.String(value), `"`, `\"`),
|
||||
)
|
||||
return true
|
||||
})
|
||||
return tag
|
||||
}
|
||||
413
cmd/gf/internal/cmd/genpbentity/genpbentity.go
Normal file
413
cmd/gf/internal/cmd/genpbentity/genpbentity.go
Normal file
@ -0,0 +1,413 @@
|
||||
package genpbentity
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
)
|
||||
|
||||
type (
|
||||
CGenPbEntity struct{}
|
||||
CGenPbEntityInput struct {
|
||||
g.Meta `name:"pbentity" config:"{CGenPbEntityConfig}" brief:"{CGenPbEntityBrief}" eg:"{CGenPbEntityEg}" ad:"{CGenPbEntityAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{CGenPbEntityBriefPath}" d:"manifest/protobuf/pbentity"`
|
||||
Package string `name:"package" short:"k" brief:"{CGenPbEntityBriefPackage}"`
|
||||
Link string `name:"link" short:"l" brief:"{CGenPbEntityBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{CGenPbEntityBriefTables}"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{CGenPbEntityBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenPbEntityBriefRemovePrefix}"`
|
||||
NameCase string `name:"nameCase" short:"n" brief:"{CGenPbEntityBriefNameCase}" d:"Camel"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{CGenPbEntityBriefJsonCase}" d:"CamelLower"`
|
||||
Option string `name:"option" short:"o" brief:"{CGenPbEntityBriefOption}"`
|
||||
}
|
||||
CGenPbEntityOutput struct{}
|
||||
|
||||
CGenPbEntityInternalInput struct {
|
||||
CGenPbEntityInput
|
||||
DB gdb.DB
|
||||
TableName string // TableName specifies the table name of the table.
|
||||
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
defaultPackageSuffix = `api/pbentity`
|
||||
CGenPbEntityConfig = `gfcli.gen.pbentity`
|
||||
CGenPbEntityBrief = `generate entity message files in protobuf3 format`
|
||||
CGenPbEntityEg = `
|
||||
gf gen pbentity
|
||||
gf gen pbentity -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
gf gen pbentity -p ./protocol/demos/entity -t user,user_detail,user_login
|
||||
gf gen pbentity -r user_ -k github.com/gogf/gf/example/protobuf
|
||||
gf gen pbentity -r user_
|
||||
`
|
||||
|
||||
CGenPbEntityAd = `
|
||||
CONFIGURATION SUPPORT
|
||||
Options are also supported by configuration file.
|
||||
It's suggested using configuration file instead of command line arguments making producing.
|
||||
The configuration node name is "gf.gen.pbentity", which also supports multiple databases, for example(config.yaml):
|
||||
gfcli:
|
||||
gen:
|
||||
- pbentity:
|
||||
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
path: "protocol/demos/entity"
|
||||
tables: "order,products"
|
||||
package: "demos"
|
||||
- pbentity:
|
||||
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/primary"
|
||||
path: "protocol/demos/entity"
|
||||
prefix: "primary_"
|
||||
tables: "user, userDetail"
|
||||
package: "demos"
|
||||
option: |
|
||||
option go_package = "protobuf/demos";
|
||||
option java_package = "protobuf/demos";
|
||||
option php_namespace = "protobuf/demos";
|
||||
`
|
||||
CGenPbEntityBriefPath = `directory path for generated files storing`
|
||||
CGenPbEntityBriefPackage = `package path for all entity proto files`
|
||||
CGenPbEntityBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
|
||||
CGenPbEntityBriefTables = `generate models only for given tables, multiple table names separated with ','`
|
||||
CGenPbEntityBriefPrefix = `add specified prefix for all entity names and entity proto files`
|
||||
CGenPbEntityBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
|
||||
CGenPbEntityBriefOption = `extra protobuf options`
|
||||
CGenPbEntityBriefGroup = `
|
||||
specifying the configuration group name of database for generated ORM instance,
|
||||
it's not necessary and the default value is "default"
|
||||
`
|
||||
|
||||
CGenPbEntityBriefNameCase = `
|
||||
case for message attribute names, default is "Camel":
|
||||
| Case | Example |
|
||||
|---------------- |--------------------|
|
||||
| Camel | AnyKindOfString |
|
||||
| CamelLower | anyKindOfString | default
|
||||
| Snake | any_kind_of_string |
|
||||
| SnakeScreaming | ANY_KIND_OF_STRING |
|
||||
| SnakeFirstUpper | rgb_code_md5 |
|
||||
| Kebab | any-kind-of-string |
|
||||
| KebabScreaming | ANY-KIND-OF-STRING |
|
||||
`
|
||||
|
||||
CGenPbEntityBriefJsonCase = `
|
||||
case for message json tag, cases are the same as "nameCase", default "CamelLower".
|
||||
set it to "none" to ignore json tag generating.
|
||||
`
|
||||
)
|
||||
|
||||
func init() {
|
||||
gtag.Sets(g.MapStrStr{
|
||||
`CGenPbEntityConfig`: CGenPbEntityConfig,
|
||||
`CGenPbEntityBrief`: CGenPbEntityBrief,
|
||||
`CGenPbEntityEg`: CGenPbEntityEg,
|
||||
`CGenPbEntityAd`: CGenPbEntityAd,
|
||||
`CGenPbEntityBriefPath`: CGenPbEntityBriefPath,
|
||||
`CGenPbEntityBriefPackage`: CGenPbEntityBriefPackage,
|
||||
`CGenPbEntityBriefLink`: CGenPbEntityBriefLink,
|
||||
`CGenPbEntityBriefTables`: CGenPbEntityBriefTables,
|
||||
`CGenPbEntityBriefPrefix`: CGenPbEntityBriefPrefix,
|
||||
`CGenPbEntityBriefRemovePrefix`: CGenPbEntityBriefRemovePrefix,
|
||||
`CGenPbEntityBriefGroup`: CGenPbEntityBriefGroup,
|
||||
`CGenPbEntityBriefNameCase`: CGenPbEntityBriefNameCase,
|
||||
`CGenPbEntityBriefJsonCase`: CGenPbEntityBriefJsonCase,
|
||||
`CGenPbEntityBriefOption`: CGenPbEntityBriefOption,
|
||||
})
|
||||
}
|
||||
|
||||
func (c CGenPbEntity) PbEntity(ctx context.Context, in CGenPbEntityInput) (out *CGenPbEntityOutput, err error) {
|
||||
var (
|
||||
config = g.Cfg()
|
||||
)
|
||||
if config.Available(ctx) {
|
||||
v := config.MustGet(ctx, CGenPbEntityConfig)
|
||||
if v.IsSlice() {
|
||||
for i := 0; i < len(v.Interfaces()); i++ {
|
||||
doGenPbEntityForArray(ctx, i, in)
|
||||
}
|
||||
} else {
|
||||
doGenPbEntityForArray(ctx, -1, in)
|
||||
}
|
||||
} else {
|
||||
doGenPbEntityForArray(ctx, -1, in)
|
||||
}
|
||||
mlog.Print("done!")
|
||||
return
|
||||
}
|
||||
|
||||
func doGenPbEntityForArray(ctx context.Context, index int, in CGenPbEntityInput) {
|
||||
var (
|
||||
err error
|
||||
db gdb.DB
|
||||
)
|
||||
if index >= 0 {
|
||||
err = g.Cfg().MustGet(
|
||||
ctx,
|
||||
fmt.Sprintf(`%s.%d`, CGenPbEntityConfig, index),
|
||||
).Scan(&in)
|
||||
if err != nil {
|
||||
mlog.Fatalf(`invalid configuration of "%s": %+v`, CGenPbEntityConfig, err)
|
||||
}
|
||||
}
|
||||
if in.Package == "" {
|
||||
mlog.Debug(`package parameter is empty, trying calculating the package path using go.mod`)
|
||||
if !gfile.Exists("go.mod") {
|
||||
mlog.Fatal("go.mod does not exist in current working directory")
|
||||
}
|
||||
var (
|
||||
modName string
|
||||
goModContent = gfile.GetContents("go.mod")
|
||||
match, _ = gregex.MatchString(`^module\s+(.+)\s*`, goModContent)
|
||||
)
|
||||
if len(match) > 1 {
|
||||
modName = gstr.Trim(match[1])
|
||||
in.Package = modName + "/" + defaultPackageSuffix
|
||||
} else {
|
||||
mlog.Fatal("module name does not found in go.mod")
|
||||
}
|
||||
}
|
||||
removePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, ",")
|
||||
// It uses user passed database configuration.
|
||||
if in.Link != "" {
|
||||
var (
|
||||
tempGroup = gtime.TimestampNanoStr()
|
||||
match, _ = gregex.MatchString(`([a-z]+):(.+)`, in.Link)
|
||||
)
|
||||
if len(match) == 3 {
|
||||
gdb.AddConfigNode(tempGroup, gdb.ConfigNode{
|
||||
Type: gstr.Trim(match[1]),
|
||||
Link: gstr.Trim(match[2]),
|
||||
})
|
||||
db, _ = gdb.Instance(tempGroup)
|
||||
}
|
||||
} else {
|
||||
db = g.DB()
|
||||
}
|
||||
if db == nil {
|
||||
mlog.Fatal("database initialization failed")
|
||||
}
|
||||
|
||||
tableNames := ([]string)(nil)
|
||||
if in.Tables != "" {
|
||||
tableNames = gstr.SplitAndTrim(in.Tables, ",")
|
||||
} else {
|
||||
tableNames, err = db.Tables(context.TODO())
|
||||
if err != nil {
|
||||
mlog.Fatalf("fetching tables failed: \n %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, tableName := range tableNames {
|
||||
newTableName := tableName
|
||||
for _, v := range removePrefixArray {
|
||||
newTableName = gstr.TrimLeftStr(newTableName, v, 1)
|
||||
}
|
||||
generatePbEntityContentFile(ctx, CGenPbEntityInternalInput{
|
||||
CGenPbEntityInput: in,
|
||||
DB: db,
|
||||
TableName: tableName,
|
||||
NewTableName: newTableName,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// generatePbEntityContentFile generates the protobuf files for given table.
|
||||
func generatePbEntityContentFile(ctx context.Context, in CGenPbEntityInternalInput) {
|
||||
fieldMap, err := in.DB.TableFields(ctx, in.TableName)
|
||||
if err != nil {
|
||||
mlog.Fatalf("fetching tables fields failed for table '%s':\n%v", in.TableName, err)
|
||||
}
|
||||
// Change the `newTableName` if `Prefix` is given.
|
||||
newTableName := in.Prefix + in.NewTableName
|
||||
var (
|
||||
imports string
|
||||
tableNameCamelCase = gstr.CaseCamel(newTableName)
|
||||
tableNameSnakeCase = gstr.CaseSnake(newTableName)
|
||||
entityMessageDefine = generateEntityMessageDefinition(tableNameCamelCase, fieldMap, in)
|
||||
fileName = gstr.Trim(tableNameSnakeCase, "-_.")
|
||||
path = gfile.Join(in.Path, fileName+".proto")
|
||||
)
|
||||
if gstr.Contains(entityMessageDefine, "google.protobuf.Timestamp") {
|
||||
imports = `import "google/protobuf/timestamp.proto";`
|
||||
}
|
||||
entityContent := gstr.ReplaceByMap(getTplPbEntityContent(""), g.MapStrStr{
|
||||
"{Imports}": imports,
|
||||
"{PackageName}": gfile.Basename(in.Package),
|
||||
"{GoPackage}": in.Package,
|
||||
"{OptionContent}": in.Option,
|
||||
"{EntityMessage}": entityMessageDefine,
|
||||
})
|
||||
if err := gfile.PutContents(path, strings.TrimSpace(entityContent)); err != nil {
|
||||
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
|
||||
} else {
|
||||
mlog.Print("generated:", path)
|
||||
}
|
||||
}
|
||||
|
||||
// generateEntityMessageDefinition generates and returns the message definition for specified table.
|
||||
func generateEntityMessageDefinition(entityName string, fieldMap map[string]*gdb.TableField, in CGenPbEntityInternalInput) string {
|
||||
var (
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
array = make([][]string, len(fieldMap))
|
||||
names = sortFieldKeyForPbEntity(fieldMap)
|
||||
)
|
||||
for index, name := range names {
|
||||
array[index] = generateMessageFieldForPbEntity(index+1, fieldMap[name], in)
|
||||
}
|
||||
tw := tablewriter.NewWriter(buffer)
|
||||
tw.SetBorder(false)
|
||||
tw.SetRowLine(false)
|
||||
tw.SetAutoWrapText(false)
|
||||
tw.SetColumnSeparator("")
|
||||
tw.AppendBulk(array)
|
||||
tw.Render()
|
||||
stContent := buffer.String()
|
||||
// Let's do this hack of table writer for indent!
|
||||
stContent = gstr.Replace(stContent, " #", "")
|
||||
buffer.Reset()
|
||||
buffer.WriteString(fmt.Sprintf("message %s {\n", entityName))
|
||||
buffer.WriteString(stContent)
|
||||
buffer.WriteString("}")
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// generateMessageFieldForPbEntity generates and returns the message definition for specified field.
|
||||
func generateMessageFieldForPbEntity(index int, field *gdb.TableField, in CGenPbEntityInternalInput) []string {
|
||||
var (
|
||||
typeName string
|
||||
comment string
|
||||
jsonTagStr string
|
||||
err error
|
||||
ctx = gctx.GetInitCtx()
|
||||
)
|
||||
typeName, err = in.DB.CheckLocalTypeForField(ctx, field.Type, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var typeMapping = map[string]string{
|
||||
gdb.LocalTypeString: "string",
|
||||
gdb.LocalTypeDate: "google.protobuf.Timestamp",
|
||||
gdb.LocalTypeDatetime: "google.protobuf.Timestamp",
|
||||
gdb.LocalTypeInt: "int32",
|
||||
gdb.LocalTypeUint: "uint32",
|
||||
gdb.LocalTypeInt64: "int64",
|
||||
gdb.LocalTypeUint64: "uint64",
|
||||
gdb.LocalTypeIntSlice: "repeated int32",
|
||||
gdb.LocalTypeInt64Slice: "repeated int64",
|
||||
gdb.LocalTypeUint64Slice: "repeated uint64",
|
||||
gdb.LocalTypeInt64Bytes: "repeated int64",
|
||||
gdb.LocalTypeUint64Bytes: "repeated uint64",
|
||||
gdb.LocalTypeFloat32: "float32",
|
||||
gdb.LocalTypeFloat64: "float64",
|
||||
gdb.LocalTypeBytes: "[]byte",
|
||||
gdb.LocalTypeBool: "bool",
|
||||
gdb.LocalTypeJson: "string",
|
||||
gdb.LocalTypeJsonb: "string",
|
||||
}
|
||||
typeName = typeMapping[typeName]
|
||||
if typeName == "" {
|
||||
typeName = "string"
|
||||
}
|
||||
|
||||
comment = gstr.ReplaceByArray(field.Comment, g.SliceStr{
|
||||
"\n", " ",
|
||||
"\r", " ",
|
||||
})
|
||||
comment = gstr.Trim(comment)
|
||||
comment = gstr.Replace(comment, `\n`, " ")
|
||||
comment, _ = gregex.ReplaceString(`\s{2,}`, ` `, comment)
|
||||
if jsonTagName := formatCase(field.Name, in.JsonCase); jsonTagName != "" {
|
||||
// beautiful indent.
|
||||
if index < 10 {
|
||||
// 3 spaces
|
||||
jsonTagStr = " " + jsonTagStr
|
||||
} else if index < 100 {
|
||||
// 2 spaces
|
||||
jsonTagStr = " " + jsonTagStr
|
||||
} else {
|
||||
// 1 spaces
|
||||
jsonTagStr = " " + jsonTagStr
|
||||
}
|
||||
}
|
||||
return []string{
|
||||
" #" + typeName,
|
||||
" #" + formatCase(field.Name, in.NameCase),
|
||||
" #= " + gconv.String(index) + jsonTagStr + ";",
|
||||
" #" + fmt.Sprintf(`// %s`, comment),
|
||||
}
|
||||
}
|
||||
|
||||
func getTplPbEntityContent(tplEntityPath string) string {
|
||||
if tplEntityPath != "" {
|
||||
return gfile.GetContents(tplEntityPath)
|
||||
}
|
||||
return consts.TemplatePbEntityMessageContent
|
||||
}
|
||||
|
||||
// formatCase call gstr.Case* function to convert the s to specified case.
|
||||
func formatCase(str, caseStr string) string {
|
||||
switch gstr.ToLower(caseStr) {
|
||||
case gstr.ToLower("Camel"):
|
||||
return gstr.CaseCamel(str)
|
||||
|
||||
case gstr.ToLower("CamelLower"):
|
||||
return gstr.CaseCamelLower(str)
|
||||
|
||||
case gstr.ToLower("Kebab"):
|
||||
return gstr.CaseKebab(str)
|
||||
|
||||
case gstr.ToLower("KebabScreaming"):
|
||||
return gstr.CaseKebabScreaming(str)
|
||||
|
||||
case gstr.ToLower("Snake"):
|
||||
return gstr.CaseSnake(str)
|
||||
|
||||
case gstr.ToLower("SnakeFirstUpper"):
|
||||
return gstr.CaseSnakeFirstUpper(str)
|
||||
|
||||
case gstr.ToLower("SnakeScreaming"):
|
||||
return gstr.CaseSnakeScreaming(str)
|
||||
|
||||
case "none":
|
||||
return ""
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func sortFieldKeyForPbEntity(fieldMap map[string]*gdb.TableField) []string {
|
||||
names := make(map[int]string)
|
||||
for _, field := range fieldMap {
|
||||
names[field.Index] = field.Name
|
||||
}
|
||||
var (
|
||||
result = make([]string, len(names))
|
||||
i = 0
|
||||
j = 0
|
||||
)
|
||||
for {
|
||||
if len(names) == 0 {
|
||||
break
|
||||
}
|
||||
if val, ok := names[i]; ok {
|
||||
result[j] = val
|
||||
j++
|
||||
delete(names, i)
|
||||
}
|
||||
i++
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -4,8 +4,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/container/gset"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@ -16,6 +14,9 @@ import (
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -188,6 +189,10 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
|
||||
generatedDstFilePathSet.Add(dstFilePath)
|
||||
for _, file := range files {
|
||||
fileContent = gfile.GetContents(file)
|
||||
fileContent, err := gregex.ReplaceString(`/[/|\*](.+)`, "", fileContent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Calculate imported packages of source go files.
|
||||
err = c.calculateImportedPackages(fileContent, srcImportedPackages)
|
||||
if err != nil {
|
||||
@ -253,7 +258,7 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
|
||||
}
|
||||
|
||||
// Replace v1 to v2 for GoFrame.
|
||||
if err = c.replaceGeneratedServiceContentGFV2(in); err != nil {
|
||||
if err = utils.ReplaceGeneratedContentGFV2(in.DstFolder); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mlog.Printf(`gofmt go files in "%s"`, in.DstFolder)
|
||||
@ -263,14 +268,3 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
|
||||
mlog.Print(`done!`)
|
||||
return
|
||||
}
|
||||
|
||||
func (c CGenService) replaceGeneratedServiceContentGFV2(in CGenServiceInput) (err error) {
|
||||
return gfile.ReplaceDirFunc(func(path, content string) string {
|
||||
if gstr.Contains(content, `"github.com/gogf/gf`) && !gstr.Contains(content, `"github.com/gogf/gf/v2`) {
|
||||
content = gstr.Replace(content, `"github.com/gogf/gf"`, `"github.com/gogf/gf/v2"`)
|
||||
content = gstr.Replace(content, `"github.com/gogf/gf/`, `"github.com/gogf/gf/v2/`)
|
||||
return content
|
||||
}
|
||||
return content
|
||||
}, in.DstFolder, "*.go", false)
|
||||
}
|
||||
|
||||
@ -3,14 +3,15 @@ package genservice
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
)
|
||||
|
||||
type generateServiceFilesInput struct {
|
||||
@ -55,7 +56,7 @@ func (c CGenService) generateServiceFile(in generateServiceFilesInput) (ok bool,
|
||||
generatingInterfaceCheck string
|
||||
)
|
||||
// Variable definitions.
|
||||
for structName, _ := range in.SrcStructFunctions {
|
||||
for structName := range in.SrcStructFunctions {
|
||||
generatingInterfaceCheck = fmt.Sprintf(`[^\w\d]+%s.I%s[^\w\d]`, in.DstPackageName, structName)
|
||||
if gregex.IsMatchString(generatingInterfaceCheck, generatedContent) {
|
||||
continue
|
||||
@ -74,7 +75,7 @@ func (c CGenService) generateServiceFile(in generateServiceFilesInput) (ok bool,
|
||||
generatedContent += "\n"
|
||||
}
|
||||
// Variable register function definitions.
|
||||
for structName, _ := range in.SrcStructFunctions {
|
||||
for structName := range in.SrcStructFunctions {
|
||||
generatingInterfaceCheck = fmt.Sprintf(`[^\w\d]+%s.I%s[^\w\d]`, in.DstPackageName, structName)
|
||||
if gregex.IsMatchString(generatingInterfaceCheck, generatedContent) {
|
||||
continue
|
||||
|
||||
@ -102,7 +102,7 @@ func (dao *{TplTableNameCamelCase}Dao) Ctx(ctx context.Context) *gdb.Model {
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function f
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *{TplTableNameCamelCase}Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) {
|
||||
func (dao *{TplTableNameCamelCase}Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
`
|
||||
|
||||
@ -9,9 +9,9 @@ syntax = "proto3";
|
||||
|
||||
package {PackageName};
|
||||
|
||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
option go_package = "{GoPackage}";
|
||||
{OptionContent}
|
||||
{Imports}
|
||||
|
||||
{EntityMessage}
|
||||
`
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -5,8 +5,6 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/container/gset"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@ -15,6 +13,9 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -28,6 +29,7 @@ type serviceInstallAvailablePath struct {
|
||||
filePath string
|
||||
writable bool
|
||||
installed bool
|
||||
IsSelf bool
|
||||
}
|
||||
|
||||
func (s serviceInstall) Run(ctx context.Context) (err error) {
|
||||
@ -118,33 +120,26 @@ func (s serviceInstall) Run(ctx context.Context) (err error) {
|
||||
dstPath := paths[selectedID]
|
||||
|
||||
// Install the new binary.
|
||||
mlog.Debugf(`copy file from "%s" to "%s"`, gfile.SelfPath(), dstPath.filePath)
|
||||
err = gfile.CopyFile(gfile.SelfPath(), dstPath.filePath)
|
||||
if err != nil {
|
||||
mlog.Printf("install gf binary to '%s' failed: %v", dstPath.dirPath, err)
|
||||
mlog.Printf("you can manually install gf by copying the binary to folder: %s", dstPath.dirPath)
|
||||
} else {
|
||||
mlog.Printf("gf binary is successfully installed to: %s", dstPath.dirPath)
|
||||
}
|
||||
|
||||
// Uninstall the old binary.
|
||||
for _, path := range paths {
|
||||
// Do not delete myself.
|
||||
if path.filePath != "" && path.filePath != dstPath.filePath && gfile.SelfPath() != path.filePath {
|
||||
_ = gfile.Remove(path.filePath)
|
||||
}
|
||||
mlog.Printf("gf binary is successfully installed to: %s", dstPath.filePath)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// IsInstalled checks and returns whether the binary is installed.
|
||||
func (s serviceInstall) IsInstalled() bool {
|
||||
func (s serviceInstall) IsInstalled() (*serviceInstallAvailablePath, bool) {
|
||||
paths := s.getAvailablePaths()
|
||||
for _, aPath := range paths {
|
||||
if aPath.installed {
|
||||
return true
|
||||
return &aPath, true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// getGoPathBinFilePath retrieves ad returns the GOPATH/bin path for binary.
|
||||
@ -220,6 +215,7 @@ func (s serviceInstall) checkAndAppendToAvailablePath(folderPaths []serviceInsta
|
||||
filePath = gfile.Join(dirPath, binaryFileName)
|
||||
writable = gfile.IsWritable(dirPath)
|
||||
installed = gfile.Exists(filePath)
|
||||
self = gfile.SelfPath() == filePath
|
||||
)
|
||||
if !writable && !installed {
|
||||
return folderPaths
|
||||
@ -231,5 +227,6 @@ func (s serviceInstall) checkAndAppendToAvailablePath(folderPaths []serviceInsta
|
||||
writable: writable,
|
||||
filePath: filePath,
|
||||
installed: installed,
|
||||
IsSelf: self,
|
||||
})
|
||||
}
|
||||
|
||||
@ -1,11 +1,15 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"golang.org/x/tools/imports"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"golang.org/x/tools/imports"
|
||||
)
|
||||
|
||||
// GoFmt formats the source file and adds or removes import statements as necessary.
|
||||
@ -35,6 +39,13 @@ func GoFmt(path string) {
|
||||
}
|
||||
}
|
||||
|
||||
// GoModTidy executes `go mod tidy` at specified directory `dirPath`.
|
||||
func GoModTidy(ctx context.Context, dirPath string) error {
|
||||
command := fmt.Sprintf(`cd %s && go mod tidy`, dirPath)
|
||||
err := gproc.ShellRun(ctx, command)
|
||||
return err
|
||||
}
|
||||
|
||||
// IsFileDoNotEdit checks and returns whether file contains `do not edit` key.
|
||||
func IsFileDoNotEdit(filePath string) bool {
|
||||
if !gfile.Exists(filePath) {
|
||||
@ -42,3 +53,16 @@ func IsFileDoNotEdit(filePath string) bool {
|
||||
}
|
||||
return gstr.Contains(gfile.GetContents(filePath), consts.DoNotEditKey)
|
||||
}
|
||||
|
||||
// ReplaceGeneratedContentGFV2 replaces generated go content from goframe v1 to v2.
|
||||
func ReplaceGeneratedContentGFV2(folderPath string) (err error) {
|
||||
return gfile.ReplaceDirFunc(func(path, content string) string {
|
||||
if gstr.Contains(content, `"github.com/gogf/gf`) && !gstr.Contains(content, `"github.com/gogf/gf/v2`) {
|
||||
content = gstr.Replace(content, `"github.com/gogf/gf"`, `"github.com/gogf/gf/v2"`)
|
||||
content = gstr.Replace(content, `"github.com/gogf/gf/`, `"github.com/gogf/gf/v2/`)
|
||||
content = gstr.Replace(content, `"github.com/gogf/gf/v2/contrib/`, `"github.com/gogf/gf/contrib/`)
|
||||
return content
|
||||
}
|
||||
return content
|
||||
}, folderPath, "*.go", true)
|
||||
}
|
||||
|
||||
98
cmd/gf/internal/utility/utils/utils_http_download.go
Normal file
98
cmd/gf/internal/utility/utils/utils_http_download.go
Normal file
@ -0,0 +1,98 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
)
|
||||
|
||||
// HTTPDownloadFileWithPercent downloads target url file to local path with percent process printing.
|
||||
func HTTPDownloadFileWithPercent(url string, localSaveFilePath string) error {
|
||||
start := time.Now()
|
||||
out, err := os.Create(localSaveFilePath)
|
||||
if err != nil {
|
||||
return gerror.Wrapf(err, `download "%s" to "%s" failed`, url, localSaveFilePath)
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
headResp, err := http.Head(url)
|
||||
if err != nil {
|
||||
return gerror.Wrapf(err, `download "%s" to "%s" failed`, url, localSaveFilePath)
|
||||
}
|
||||
defer headResp.Body.Close()
|
||||
|
||||
size, err := strconv.Atoi(headResp.Header.Get("Content-Length"))
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "retrieve Content-Length failed")
|
||||
}
|
||||
doneCh := make(chan int64)
|
||||
|
||||
go doPrintDownloadPercent(doneCh, localSaveFilePath, int64(size))
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return gerror.Wrapf(err, `download "%s" to "%s" failed`, url, localSaveFilePath)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
wroteBytesCount, err := io.Copy(out, resp.Body)
|
||||
if err != nil {
|
||||
return gerror.Wrapf(err, `download "%s" to "%s" failed`, url, localSaveFilePath)
|
||||
}
|
||||
|
||||
doneCh <- wroteBytesCount
|
||||
elapsed := time.Since(start)
|
||||
if elapsed > time.Minute {
|
||||
mlog.Printf(`download completed in %.0fm`, float64(elapsed)/float64(time.Minute))
|
||||
} else {
|
||||
mlog.Printf(`download completed in %.0fs`, elapsed.Seconds())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func doPrintDownloadPercent(doneCh chan int64, localSaveFilePath string, total int64) {
|
||||
var (
|
||||
stop = false
|
||||
lastPercentFmt string
|
||||
)
|
||||
for {
|
||||
select {
|
||||
case <-doneCh:
|
||||
stop = true
|
||||
|
||||
default:
|
||||
file, err := os.Open(localSaveFilePath)
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
fi, err := file.Stat()
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
size := fi.Size()
|
||||
if size == 0 {
|
||||
size = 1
|
||||
}
|
||||
var (
|
||||
percent = float64(size) / float64(total) * 100
|
||||
percentFmt = fmt.Sprintf(`%.0f`, percent) + "%"
|
||||
)
|
||||
if lastPercentFmt != percentFmt {
|
||||
lastPercentFmt = percentFmt
|
||||
mlog.Print(percentFmt)
|
||||
}
|
||||
}
|
||||
|
||||
if stop {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
@ -2,16 +2,17 @@ package main
|
||||
|
||||
import (
|
||||
_ "github.com/gogf/gf/cmd/gf/v2/internal/packed"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/cmd"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/cmd"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -52,7 +53,9 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
err = command.AddObject(
|
||||
cmd.Up,
|
||||
cmd.Env,
|
||||
cmd.Fix,
|
||||
cmd.Run,
|
||||
cmd.Gen,
|
||||
cmd.Tpl,
|
||||
@ -66,7 +69,10 @@ func main() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
command.Run(ctx)
|
||||
err = command.RunWithError(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// zsh alias "git fetch" conflicts checks.
|
||||
|
||||
@ -53,16 +53,16 @@ func NewArraySize(size int, cap int, safe ...bool) *Array {
|
||||
}
|
||||
}
|
||||
|
||||
// NewArrayRange creates and returns a array by a range from `start` to `end`
|
||||
// NewArrayRange creates and returns an array by a range from `start` to `end`
|
||||
// with step value `step`.
|
||||
func NewArrayRange(start, end, step int, safe ...bool) *Array {
|
||||
if step == 0 {
|
||||
panic(fmt.Sprintf(`invalid step value: %d`, step))
|
||||
}
|
||||
slice := make([]interface{}, (end-start+1)/step)
|
||||
slice := make([]interface{}, 0)
|
||||
index := 0
|
||||
for i := start; i <= end; i += step {
|
||||
slice[index] = i
|
||||
slice = append(slice, i)
|
||||
index++
|
||||
}
|
||||
return NewArrayFrom(slice, safe...)
|
||||
@ -173,28 +173,28 @@ func (a *Array) SortFunc(less func(v1, v2 interface{}) bool) *Array {
|
||||
return a
|
||||
}
|
||||
|
||||
// InsertBefore inserts the `value` to the front of `index`.
|
||||
func (a *Array) InsertBefore(index int, value interface{}) error {
|
||||
// InsertBefore inserts the `values` to the front of `index`.
|
||||
func (a *Array) InsertBefore(index int, values ...interface{}) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
|
||||
}
|
||||
rear := append([]interface{}{}, a.array[index:]...)
|
||||
a.array = append(a.array[0:index], value)
|
||||
a.array = append(a.array[0:index], values...)
|
||||
a.array = append(a.array, rear...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertAfter inserts the `value` to the back of `index`.
|
||||
func (a *Array) InsertAfter(index int, value interface{}) error {
|
||||
// InsertAfter inserts the `values` to the back of `index`.
|
||||
func (a *Array) InsertAfter(index int, values ...interface{}) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
|
||||
}
|
||||
rear := append([]interface{}{}, a.array[index+1:]...)
|
||||
a.array = append(a.array[0:index+1], value)
|
||||
a.array = append(a.array[0:index+1], values...)
|
||||
a.array = append(a.array, rear...)
|
||||
return nil
|
||||
}
|
||||
@ -233,13 +233,26 @@ func (a *Array) doRemoveWithoutLock(index int) (value interface{}, found bool) {
|
||||
// RemoveValue removes an item by value.
|
||||
// It returns true if value is found in the array, or else false if not found.
|
||||
func (a *Array) RemoveValue(value interface{}) bool {
|
||||
if i := a.Search(value); i != -1 {
|
||||
a.Remove(i)
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if i := a.doSearchWithoutLock(value); i != -1 {
|
||||
a.doRemoveWithoutLock(i)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RemoveValues removes multiple items by `values`.
|
||||
func (a *Array) RemoveValues(values ...interface{}) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
for _, value := range values {
|
||||
if i := a.doSearchWithoutLock(value); i != -1 {
|
||||
a.doRemoveWithoutLock(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PushLeft pushes one or multiple items to the beginning of array.
|
||||
func (a *Array) PushLeft(value ...interface{}) *Array {
|
||||
a.mu.Lock()
|
||||
@ -487,6 +500,10 @@ func (a *Array) Contains(value interface{}) bool {
|
||||
func (a *Array) Search(value interface{}) int {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
return a.doSearchWithoutLock(value)
|
||||
}
|
||||
|
||||
func (a *Array) doSearchWithoutLock(value interface{}) int {
|
||||
if len(a.array) == 0 {
|
||||
return -1
|
||||
}
|
||||
@ -778,6 +795,24 @@ func (a *Array) UnmarshalValue(value interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Filter `filter func(value interface{}, index int) bool` filter array, value
|
||||
// means the value of the current element, the index of the current original
|
||||
// color of value, when the custom function returns True, the element will be
|
||||
// filtered, otherwise it will not be filtered, `Filter` function returns a new
|
||||
// array, will not modify the original array.
|
||||
func (a *Array) Filter(filter func(index int, value interface{}) bool) *Array {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
for i := 0; i < len(a.array); {
|
||||
if filter(i, a.array[i]) {
|
||||
a.array = append(a.array[:i], a.array[i+1:]...)
|
||||
} else {
|
||||
i++
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// FilterNil removes all nil value of the array.
|
||||
func (a *Array) FilterNil() *Array {
|
||||
a.mu.Lock()
|
||||
|
||||
@ -45,16 +45,16 @@ func NewIntArraySize(size int, cap int, safe ...bool) *IntArray {
|
||||
}
|
||||
}
|
||||
|
||||
// NewIntArrayRange creates and returns a array by a range from `start` to `end`
|
||||
// NewIntArrayRange creates and returns an array by a range from `start` to `end`
|
||||
// with step value `step`.
|
||||
func NewIntArrayRange(start, end, step int, safe ...bool) *IntArray {
|
||||
if step == 0 {
|
||||
panic(fmt.Sprintf(`invalid step value: %d`, step))
|
||||
}
|
||||
slice := make([]int, (end-start+1)/step)
|
||||
slice := make([]int, 0)
|
||||
index := 0
|
||||
for i := start; i <= end; i += step {
|
||||
slice[index] = i
|
||||
slice = append(slice, i)
|
||||
index++
|
||||
}
|
||||
return NewIntArrayFrom(slice, safe...)
|
||||
@ -168,28 +168,28 @@ func (a *IntArray) SortFunc(less func(v1, v2 int) bool) *IntArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// InsertBefore inserts the `value` to the front of `index`.
|
||||
func (a *IntArray) InsertBefore(index int, value int) error {
|
||||
// InsertBefore inserts the `values` to the front of `index`.
|
||||
func (a *IntArray) InsertBefore(index int, values ...int) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
|
||||
}
|
||||
rear := append([]int{}, a.array[index:]...)
|
||||
a.array = append(a.array[0:index], value)
|
||||
a.array = append(a.array[0:index], values...)
|
||||
a.array = append(a.array, rear...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertAfter inserts the `value` to the back of `index`.
|
||||
func (a *IntArray) InsertAfter(index int, value int) error {
|
||||
func (a *IntArray) InsertAfter(index int, values ...int) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
|
||||
}
|
||||
rear := append([]int{}, a.array[index+1:]...)
|
||||
a.array = append(a.array[0:index+1], value)
|
||||
a.array = append(a.array[0:index+1], values...)
|
||||
a.array = append(a.array, rear...)
|
||||
return nil
|
||||
}
|
||||
@ -228,13 +228,26 @@ func (a *IntArray) doRemoveWithoutLock(index int) (value int, found bool) {
|
||||
// RemoveValue removes an item by value.
|
||||
// It returns true if value is found in the array, or else false if not found.
|
||||
func (a *IntArray) RemoveValue(value int) bool {
|
||||
if i := a.Search(value); i != -1 {
|
||||
_, found := a.Remove(i)
|
||||
return found
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if i := a.doSearchWithoutLock(value); i != -1 {
|
||||
a.doRemoveWithoutLock(i)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RemoveValues removes multiple items by `values`.
|
||||
func (a *IntArray) RemoveValues(values ...int) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
for _, value := range values {
|
||||
if i := a.doSearchWithoutLock(value); i != -1 {
|
||||
a.doRemoveWithoutLock(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PushLeft pushes one or multiple items to the beginning of array.
|
||||
func (a *IntArray) PushLeft(value ...int) *IntArray {
|
||||
a.mu.Lock()
|
||||
@ -497,6 +510,10 @@ func (a *IntArray) Contains(value int) bool {
|
||||
func (a *IntArray) Search(value int) int {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
return a.doSearchWithoutLock(value)
|
||||
}
|
||||
|
||||
func (a *IntArray) doSearchWithoutLock(value int) int {
|
||||
if len(a.array) == 0 {
|
||||
return -1
|
||||
}
|
||||
@ -771,6 +788,24 @@ func (a *IntArray) UnmarshalValue(value interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Filter `filter func(value int, index int) bool` filter array, value
|
||||
// means the value of the current element, the index of the current original
|
||||
// color of value, when the custom function returns True, the element will be
|
||||
// filtered, otherwise it will not be filtered, `Filter` function returns a new
|
||||
// array, will not modify the original array.
|
||||
func (a *IntArray) Filter(filter func(index int, value int) bool) *IntArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
for i := 0; i < len(a.array); {
|
||||
if filter(i, a.array[i]) {
|
||||
a.array = append(a.array[:i], a.array[i+1:]...)
|
||||
} else {
|
||||
i++
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// FilterEmpty removes all zero value of the array.
|
||||
func (a *IntArray) FilterEmpty() *IntArray {
|
||||
a.mu.Lock()
|
||||
|
||||
@ -155,28 +155,28 @@ func (a *StrArray) SortFunc(less func(v1, v2 string) bool) *StrArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// InsertBefore inserts the `value` to the front of `index`.
|
||||
func (a *StrArray) InsertBefore(index int, value string) error {
|
||||
// InsertBefore inserts the `values` to the front of `index`.
|
||||
func (a *StrArray) InsertBefore(index int, values ...string) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
|
||||
}
|
||||
rear := append([]string{}, a.array[index:]...)
|
||||
a.array = append(a.array[0:index], value)
|
||||
a.array = append(a.array[0:index], values...)
|
||||
a.array = append(a.array, rear...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertAfter inserts the `value` to the back of `index`.
|
||||
func (a *StrArray) InsertAfter(index int, value string) error {
|
||||
// InsertAfter inserts the `values` to the back of `index`.
|
||||
func (a *StrArray) InsertAfter(index int, values ...string) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if index < 0 || index >= len(a.array) {
|
||||
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
|
||||
}
|
||||
rear := append([]string{}, a.array[index+1:]...)
|
||||
a.array = append(a.array[0:index+1], value)
|
||||
a.array = append(a.array[0:index+1], values...)
|
||||
a.array = append(a.array, rear...)
|
||||
return nil
|
||||
}
|
||||
@ -222,6 +222,17 @@ func (a *StrArray) RemoveValue(value string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// RemoveValues removes multiple items by `values`.
|
||||
func (a *StrArray) RemoveValues(values ...string) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
for _, value := range values {
|
||||
if i := a.doSearchWithoutLock(value); i != -1 {
|
||||
a.doRemoveWithoutLock(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PushLeft pushes one or multiple items to the beginning of array.
|
||||
func (a *StrArray) PushLeft(value ...string) *StrArray {
|
||||
a.mu.Lock()
|
||||
@ -499,6 +510,10 @@ func (a *StrArray) ContainsI(value string) bool {
|
||||
func (a *StrArray) Search(value string) int {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
return a.doSearchWithoutLock(value)
|
||||
}
|
||||
|
||||
func (a *StrArray) doSearchWithoutLock(value string) int {
|
||||
if len(a.array) == 0 {
|
||||
return -1
|
||||
}
|
||||
@ -784,6 +799,24 @@ func (a *StrArray) UnmarshalValue(value interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Filter `filter func(value string, index int) bool` filter array, value
|
||||
// means the value of the current element, the index of the current original
|
||||
// color of value, when the custom function returns True, the element will be
|
||||
// filtered, otherwise it will not be filtered, `Filter` function returns a new
|
||||
// array, will not modify the original array.
|
||||
func (a *StrArray) Filter(filter func(index int, value string) bool) *StrArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
for i := 0; i < len(a.array); {
|
||||
if filter(i, a.array[i]) {
|
||||
a.array = append(a.array[:i], a.array[i+1:]...)
|
||||
} else {
|
||||
i++
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// FilterEmpty removes all empty string value of the array.
|
||||
func (a *StrArray) FilterEmpty() *StrArray {
|
||||
a.mu.Lock()
|
||||
|
||||
@ -55,16 +55,16 @@ func NewSortedArraySize(cap int, comparator func(a, b interface{}) int, safe ...
|
||||
}
|
||||
}
|
||||
|
||||
// NewSortedArrayRange creates and returns a array by a range from `start` to `end`
|
||||
// NewSortedArrayRange creates and returns an array by a range from `start` to `end`
|
||||
// with step value `step`.
|
||||
func NewSortedArrayRange(start, end, step int, comparator func(a, b interface{}) int, safe ...bool) *SortedArray {
|
||||
if step == 0 {
|
||||
panic(fmt.Sprintf(`invalid step value: %d`, step))
|
||||
}
|
||||
slice := make([]interface{}, (end-start+1)/step)
|
||||
slice := make([]interface{}, 0)
|
||||
index := 0
|
||||
for i := start; i <= end; i += step {
|
||||
slice[index] = i
|
||||
slice = append(slice, i)
|
||||
index++
|
||||
}
|
||||
return NewSortedArrayFrom(slice, comparator, safe...)
|
||||
@ -207,13 +207,26 @@ func (a *SortedArray) doRemoveWithoutLock(index int) (value interface{}, found b
|
||||
// RemoveValue removes an item by value.
|
||||
// It returns true if value is found in the array, or else false if not found.
|
||||
func (a *SortedArray) RemoveValue(value interface{}) bool {
|
||||
if i := a.Search(value); i != -1 {
|
||||
a.Remove(i)
|
||||
return true
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if i, r := a.binSearch(value, false); r == 0 {
|
||||
_, res := a.doRemoveWithoutLock(i)
|
||||
return res
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RemoveValues removes an item by `values`.
|
||||
func (a *SortedArray) RemoveValues(values ...interface{}) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
for _, value := range values {
|
||||
if i, r := a.binSearch(value, false); r == 0 {
|
||||
a.doRemoveWithoutLock(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PopLeft pops and returns an item from the beginning of array.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *SortedArray) PopLeft() (value interface{}, found bool) {
|
||||
@ -468,7 +481,7 @@ func (a *SortedArray) binSearch(value interface{}, lock bool) (index int, result
|
||||
|
||||
// SetUnique sets unique mark to the array,
|
||||
// which means it does not contain any repeated items.
|
||||
// It also do unique check, remove all repeated items.
|
||||
// It also does unique check, remove all repeated items.
|
||||
func (a *SortedArray) SetUnique(unique bool) *SortedArray {
|
||||
oldUnique := a.unique
|
||||
a.unique = unique
|
||||
@ -748,6 +761,24 @@ func (a *SortedArray) FilterNil() *SortedArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// Filter `filter func(value interface{}, index int) bool` filter array, value
|
||||
// means the value of the current element, the index of the current original
|
||||
// color of value, when the custom function returns True, the element will be
|
||||
// filtered, otherwise it will not be filtered, `Filter` function returns a new
|
||||
// array, will not modify the original array.
|
||||
func (a *SortedArray) Filter(filter func(index int, value interface{}) bool) *SortedArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
for i := 0; i < len(a.array); {
|
||||
if filter(i, a.array[i]) {
|
||||
a.array = append(a.array[:i], a.array[i+1:]...)
|
||||
} else {
|
||||
i++
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// FilterEmpty removes all empty value of the array.
|
||||
// Values like: 0, nil, false, "", len(slice/map/chan) == 0 are considered empty.
|
||||
func (a *SortedArray) FilterEmpty() *SortedArray {
|
||||
|
||||
@ -56,16 +56,16 @@ func NewSortedIntArraySize(cap int, safe ...bool) *SortedIntArray {
|
||||
}
|
||||
}
|
||||
|
||||
// NewSortedIntArrayRange creates and returns a array by a range from `start` to `end`
|
||||
// NewSortedIntArrayRange creates and returns an array by a range from `start` to `end`
|
||||
// with step value `step`.
|
||||
func NewSortedIntArrayRange(start, end, step int, safe ...bool) *SortedIntArray {
|
||||
if step == 0 {
|
||||
panic(fmt.Sprintf(`invalid step value: %d`, step))
|
||||
}
|
||||
slice := make([]int, (end-start+1)/step)
|
||||
slice := make([]int, 0)
|
||||
index := 0
|
||||
for i := start; i <= end; i += step {
|
||||
slice[index] = i
|
||||
slice = append(slice, i)
|
||||
index++
|
||||
}
|
||||
return NewSortedIntArrayFrom(slice, safe...)
|
||||
@ -193,13 +193,26 @@ func (a *SortedIntArray) doRemoveWithoutLock(index int) (value int, found bool)
|
||||
// RemoveValue removes an item by value.
|
||||
// It returns true if value is found in the array, or else false if not found.
|
||||
func (a *SortedIntArray) RemoveValue(value int) bool {
|
||||
if i := a.Search(value); i != -1 {
|
||||
_, found := a.Remove(i)
|
||||
return found
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if i, r := a.binSearch(value, false); r == 0 {
|
||||
_, res := a.doRemoveWithoutLock(i)
|
||||
return res
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RemoveValues removes an item by `values`.
|
||||
func (a *SortedIntArray) RemoveValues(values ...int) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
for _, value := range values {
|
||||
if i, r := a.binSearch(value, false); r == 0 {
|
||||
a.doRemoveWithoutLock(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PopLeft pops and returns an item from the beginning of array.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *SortedIntArray) PopLeft() (value int, found bool) {
|
||||
@ -696,6 +709,24 @@ func (a *SortedIntArray) UnmarshalValue(value interface{}) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
// Filter `filter func(value int, index int) bool` filter array, value
|
||||
// means the value of the current element, the index of the current original
|
||||
// color of value, when the custom function returns True, the element will be
|
||||
// filtered, otherwise it will not be filtered, `Filter` function returns a new
|
||||
// array, will not modify the original array.
|
||||
func (a *SortedIntArray) Filter(filter func(index int, value int) bool) *SortedIntArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
for i := 0; i < len(a.array); {
|
||||
if filter(i, a.array[i]) {
|
||||
a.array = append(a.array[:i], a.array[i+1:]...)
|
||||
} else {
|
||||
i++
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// FilterEmpty removes all zero value of the array.
|
||||
func (a *SortedIntArray) FilterEmpty() *SortedIntArray {
|
||||
a.mu.Lock()
|
||||
|
||||
@ -179,13 +179,26 @@ func (a *SortedStrArray) doRemoveWithoutLock(index int) (value string, found boo
|
||||
// RemoveValue removes an item by value.
|
||||
// It returns true if value is found in the array, or else false if not found.
|
||||
func (a *SortedStrArray) RemoveValue(value string) bool {
|
||||
if i := a.Search(value); i != -1 {
|
||||
a.Remove(i)
|
||||
return true
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if i, r := a.binSearch(value, false); r == 0 {
|
||||
_, res := a.doRemoveWithoutLock(i)
|
||||
return res
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RemoveValues removes an item by `values`.
|
||||
func (a *SortedStrArray) RemoveValues(values ...string) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
for _, value := range values {
|
||||
if i, r := a.binSearch(value, false); r == 0 {
|
||||
a.doRemoveWithoutLock(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PopLeft pops and returns an item from the beginning of array.
|
||||
// Note that if the array is empty, the `found` is false.
|
||||
func (a *SortedStrArray) PopLeft() (value string, found bool) {
|
||||
@ -709,6 +722,24 @@ func (a *SortedStrArray) UnmarshalValue(value interface{}) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
// Filter `filter func(value string, index int) bool` filter array, value
|
||||
// means the value of the current element, the index of the current original
|
||||
// color of value, when the custom function returns True, the element will be
|
||||
// filtered, otherwise it will not be filtered, `Filter` function returns a new
|
||||
// array, will not modify the original array.
|
||||
func (a *SortedStrArray) Filter(filter func(index int, value string) bool) *SortedStrArray {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
for i := 0; i < len(a.array); {
|
||||
if filter(i, a.array[i]) {
|
||||
a.array = append(a.array[:i], a.array[i+1:]...)
|
||||
} else {
|
||||
i++
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// FilterEmpty removes all empty string value of the array.
|
||||
func (a *SortedStrArray) FilterEmpty() *SortedStrArray {
|
||||
a.mu.Lock()
|
||||
|
||||
@ -9,6 +9,8 @@ package garray_test
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
@ -261,6 +263,21 @@ func ExampleArray_Merge() {
|
||||
// [1 2 1 2 3 4 5 6 7 8 9 0]
|
||||
}
|
||||
|
||||
func ExampleArray_Filter() {
|
||||
array1 := garray.NewFrom(g.Slice{0, 1, 2, nil, "", g.Slice{}, "john"})
|
||||
array2 := garray.NewFrom(g.Slice{0, 1, 2, nil, "", g.Slice{}, "john"})
|
||||
fmt.Printf("%#v\n", array1.Filter(func(index int, value interface{}) bool {
|
||||
return empty.IsNil(value)
|
||||
}).Slice())
|
||||
fmt.Printf("%#v\n", array2.Filter(func(index int, value interface{}) bool {
|
||||
return empty.IsEmpty(value)
|
||||
}).Slice())
|
||||
|
||||
// Output:
|
||||
// []interface {}{0, 1, 2, "", []interface {}{}, "john"}
|
||||
// []interface {}{1, 2, "john"}
|
||||
}
|
||||
|
||||
func ExampleArray_FilterEmpty() {
|
||||
array1 := garray.NewFrom(g.Slice{0, 1, 2, nil, "", g.Slice{}, "john"})
|
||||
array2 := garray.NewFrom(g.Slice{0, 1, 2, nil, "", g.Slice{}, "john"})
|
||||
|
||||
@ -9,6 +9,8 @@ package garray_test
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
@ -59,7 +61,7 @@ func ExampleNewIntArrayRange() {
|
||||
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5] 5 5
|
||||
// [1 2 3 4 5] 5 8
|
||||
}
|
||||
|
||||
func ExampleNewIntArrayFrom() {
|
||||
@ -699,6 +701,25 @@ func ExampleIntArray_UnmarshalValue() {
|
||||
// &{john [96,98,97]}
|
||||
}
|
||||
|
||||
func ExampleIntArray_Filter() {
|
||||
array1 := garray.NewIntArrayFrom(g.SliceInt{10, 40, 50, 0, 0, 0, 60})
|
||||
array2 := garray.NewIntArrayFrom(g.SliceInt{10, 4, 51, 5, 45, 50, 56})
|
||||
fmt.Println(array1.Filter(func(index int, value int) bool {
|
||||
return empty.IsEmpty(value)
|
||||
}))
|
||||
fmt.Println(array2.Filter(func(index int, value int) bool {
|
||||
return value%2 == 0
|
||||
}))
|
||||
fmt.Println(array2.Filter(func(index int, value int) bool {
|
||||
return value%2 == 1
|
||||
}))
|
||||
|
||||
// Output:
|
||||
// [10,40,50,60]
|
||||
// [51,5,45]
|
||||
// []
|
||||
}
|
||||
|
||||
func ExampleIntArray_FilterEmpty() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 40, 50, 0, 0, 0, 60})
|
||||
fmt.Println(s)
|
||||
|
||||
@ -8,6 +8,9 @@ package garray_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@ -622,6 +625,22 @@ func ExampleStrArray_UnmarshalValue() {
|
||||
// &{john ["Math","English","Sport"]}
|
||||
}
|
||||
|
||||
func ExampleStrArray_Filter() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"Math", "English", "Sport"})
|
||||
s1 := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "", "c", "", "", "d"})
|
||||
fmt.Println(s1.Filter(func(index int, value string) bool {
|
||||
return empty.IsEmpty(value)
|
||||
}))
|
||||
|
||||
fmt.Println(s.Filter(func(index int, value string) bool {
|
||||
return strings.Contains(value, "h")
|
||||
}))
|
||||
|
||||
// Output:
|
||||
// ["a","b","c","d"]
|
||||
// ["Sport"]
|
||||
}
|
||||
|
||||
func ExampleStrArray_FilterEmpty() {
|
||||
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "", "c", "", "", "d"})
|
||||
fmt.Println(s.FilterEmpty())
|
||||
|
||||
@ -9,6 +9,8 @@ package garray_test
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
@ -552,6 +554,18 @@ func ExampleSortedStrArray_UnmarshalValue() {
|
||||
// &{john ["Math","English","Sport"]}
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_Filter() {
|
||||
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "a", "", "c", "", "", "d"})
|
||||
fmt.Println(s)
|
||||
fmt.Println(s.Filter(func(index int, value string) bool {
|
||||
return empty.IsEmpty(value)
|
||||
}))
|
||||
|
||||
// Output:
|
||||
// ["","","","a","b","c","d"]
|
||||
// ["a","b","c","d"]
|
||||
}
|
||||
|
||||
func ExampleSortedStrArray_FilterEmpty() {
|
||||
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "a", "", "c", "", "", "d"})
|
||||
fmt.Println(s)
|
||||
|
||||
@ -12,6 +12,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
@ -750,6 +752,15 @@ func TestArray_RemoveValue(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_RemoveValues(t *testing.T) {
|
||||
slice := g.Slice{"a", "b", "d", "c"}
|
||||
array := garray.NewArrayFrom(slice)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array.RemoveValues("a", "b", "c")
|
||||
t.Assert(array.Slice(), g.Slice{"d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_UnmarshalValue(t *testing.T) {
|
||||
type V struct {
|
||||
Name string
|
||||
@ -791,6 +802,36 @@ func TestArray_FilterNil(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Filter(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
values := g.Slice{0, 1, 2, 3, 4, "", g.Slice{}}
|
||||
array := garray.NewArrayFromCopy(values)
|
||||
t.Assert(array.Filter(func(index int, value interface{}) bool {
|
||||
return empty.IsNil(value)
|
||||
}).Slice(), values)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewArrayFromCopy(g.Slice{nil, 1, 2, 3, 4, nil})
|
||||
t.Assert(array.Filter(func(index int, value interface{}) bool {
|
||||
return empty.IsNil(value)
|
||||
}), g.Slice{1, 2, 3, 4})
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewArrayFrom(g.Slice{0, 1, 2, 3, 4, "", g.Slice{}})
|
||||
|
||||
t.Assert(array.Filter(func(index int, value interface{}) bool {
|
||||
return empty.IsEmpty(value)
|
||||
}), g.Slice{1, 2, 3, 4})
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewArrayFrom(g.Slice{1, 2, 3, 4})
|
||||
|
||||
t.Assert(array.Filter(func(index int, value interface{}) bool {
|
||||
return empty.IsEmpty(value)
|
||||
}), g.Slice{1, 2, 3, 4})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_FilterEmpty(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewArrayFrom(g.Slice{0, 1, 2, 3, 4, "", g.Slice{}})
|
||||
|
||||
@ -12,6 +12,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
@ -765,6 +767,15 @@ func TestIntArray_RemoveValue(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_RemoveValues(t *testing.T) {
|
||||
slice := g.SliceInt{10, 20, 30, 40}
|
||||
array := garray.NewIntArrayFrom(slice)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array.RemoveValues(10, 20, 40)
|
||||
t.Assert(array.Slice(), g.SliceInt{30})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_UnmarshalValue(t *testing.T) {
|
||||
type V struct {
|
||||
Name string
|
||||
@ -794,6 +805,34 @@ func TestIntArray_UnmarshalValue(t *testing.T) {
|
||||
// })
|
||||
}
|
||||
|
||||
func TestIntArray_Filter(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewIntArrayFrom(g.SliceInt{0, 1, 2, 3, 4, 0})
|
||||
t.Assert(array.Filter(func(index int, value int) bool {
|
||||
return empty.IsEmpty(value)
|
||||
}), g.SliceInt{1, 2, 3, 4})
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewIntArrayFrom(g.SliceInt{1, 2, 3, 4})
|
||||
t.Assert(array.Filter(func(index int, value int) bool {
|
||||
return empty.IsEmpty(value)
|
||||
|
||||
}), g.SliceInt{1, 2, 3, 4})
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewIntArrayFrom(g.SliceInt{1, 2, 3, 4})
|
||||
t.Assert(array.Filter(func(index int, value int) bool {
|
||||
return value%2 == 0
|
||||
}), g.SliceInt{1, 3})
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewIntArrayFrom(g.SliceInt{1, 2, 3, 4})
|
||||
t.Assert(array.Filter(func(index int, value int) bool {
|
||||
return value%2 == 1
|
||||
}), g.SliceInt{2, 4})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_FilterEmpty(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewIntArrayFrom(g.SliceInt{0, 1, 2, 3, 4, 0})
|
||||
@ -813,3 +852,14 @@ func TestIntArray_Walk(t *testing.T) {
|
||||
}), g.Slice{11, 12})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_NewIntArrayRange(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewIntArrayRange(0, 128, 4)
|
||||
t.Assert(array.String(), `[0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128]`)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewIntArrayRange(1, 128, 4)
|
||||
t.Assert(array.String(), `[1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61,65,69,73,77,81,85,89,93,97,101,105,109,113,117,121,125]`)
|
||||
})
|
||||
}
|
||||
|
||||
@ -13,6 +13,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
@ -776,6 +778,15 @@ func TestStrArray_RemoveValue(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestStrArray_RemoveValues(t *testing.T) {
|
||||
slice := g.SliceStr{"a", "b", "d", "c"}
|
||||
array := garray.NewStrArrayFrom(slice)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array.RemoveValues("a", "b", "c")
|
||||
t.Assert(array.Slice(), g.SliceStr{"d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStrArray_UnmarshalValue(t *testing.T) {
|
||||
type V struct {
|
||||
Name string
|
||||
@ -804,6 +815,20 @@ func TestStrArray_UnmarshalValue(t *testing.T) {
|
||||
t.Assert(v.Array.Slice(), g.SliceStr{"1", "2", "3"})
|
||||
})
|
||||
}
|
||||
func TestStrArray_Filter(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewStrArrayFrom(g.SliceStr{"", "1", "2", "0"})
|
||||
t.Assert(array.Filter(func(index int, value string) bool {
|
||||
return empty.IsEmpty(value)
|
||||
}), g.SliceStr{"1", "2", "0"})
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewStrArrayFrom(g.SliceStr{"1", "2"})
|
||||
t.Assert(array.Filter(func(index int, value string) bool {
|
||||
return empty.IsEmpty(value)
|
||||
}), g.SliceStr{"1", "2"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStrArray_FilterEmpty(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
|
||||
@ -13,6 +13,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
@ -869,6 +871,15 @@ func TestSortedArray_RemoveValue(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_RemoveValues(t *testing.T) {
|
||||
slice := g.Slice{"a", "b", "d", "c"}
|
||||
array := garray.NewSortedArrayFrom(slice, gutil.ComparatorString)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array.RemoveValues("a", "b", "c")
|
||||
t.Assert(array.Slice(), g.SliceStr{"d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_UnmarshalValue(t *testing.T) {
|
||||
type V struct {
|
||||
Name string
|
||||
@ -897,6 +908,33 @@ func TestSortedArray_UnmarshalValue(t *testing.T) {
|
||||
t.Assert(v.Array.Slice(), g.Slice{1, 2, 3})
|
||||
})
|
||||
}
|
||||
func TestSortedArray_Filter(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
values := g.Slice{0, 1, 2, 3, 4, "", g.Slice{}}
|
||||
array := garray.NewSortedArrayFromCopy(values, gutil.ComparatorInt)
|
||||
t.Assert(array.Filter(func(index int, value interface{}) bool {
|
||||
return empty.IsNil(value)
|
||||
}).Slice(), g.Slice{0, "", g.Slice{}, 1, 2, 3, 4})
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewSortedArrayFromCopy(g.Slice{nil, 1, 2, 3, 4, nil}, gutil.ComparatorInt)
|
||||
t.Assert(array.Filter(func(index int, value interface{}) bool {
|
||||
return empty.IsNil(value)
|
||||
}), g.Slice{1, 2, 3, 4})
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewSortedArrayFrom(g.Slice{0, 1, 2, 3, 4, "", g.Slice{}}, gutil.ComparatorInt)
|
||||
t.Assert(array.Filter(func(index int, value interface{}) bool {
|
||||
return empty.IsEmpty(value)
|
||||
}), g.Slice{1, 2, 3, 4})
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewSortedArrayFrom(g.Slice{1, 2, 3, 4}, gutil.ComparatorInt)
|
||||
t.Assert(array.Filter(func(index int, value interface{}) bool {
|
||||
return empty.IsEmpty(value)
|
||||
}), g.Slice{1, 2, 3, 4})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_FilterNil(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
|
||||
@ -12,6 +12,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
@ -737,6 +739,15 @@ func TestSortedIntArray_RemoveValue(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_RemoveValues(t *testing.T) {
|
||||
slice := g.SliceInt{10, 20, 30, 40}
|
||||
array := garray.NewSortedIntArrayFrom(slice)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array.RemoveValues(10, 40, 20)
|
||||
t.Assert(array.Slice(), g.SliceInt{30})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_UnmarshalValue(t *testing.T) {
|
||||
type V struct {
|
||||
Name string
|
||||
@ -765,6 +776,20 @@ func TestSortedIntArray_UnmarshalValue(t *testing.T) {
|
||||
t.Assert(v.Array.Slice(), g.Slice{1, 2, 3})
|
||||
})
|
||||
}
|
||||
func TestSortedIntArray_Filter(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewSortedIntArrayFrom(g.SliceInt{0, 1, 2, 3, 4, 0})
|
||||
t.Assert(array.Filter(func(index int, value int) bool {
|
||||
return empty.IsEmpty(value)
|
||||
}), g.SliceInt{1, 2, 3, 4})
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewSortedIntArrayFrom(g.SliceInt{1, 2, 3, 4})
|
||||
t.Assert(array.Filter(func(index int, value int) bool {
|
||||
return empty.IsEmpty(value)
|
||||
}), g.SliceInt{1, 2, 3, 4})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_FilterEmpty(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
|
||||
@ -9,14 +9,16 @@
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
@ -749,6 +751,15 @@ func TestSortedStrArray_RemoveValue(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_RemoveValues(t *testing.T) {
|
||||
slice := g.SliceStr{"a", "b", "d", "c"}
|
||||
array := garray.NewSortedStrArrayFrom(slice)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array.RemoveValues("a", "b", "c")
|
||||
t.Assert(array.Slice(), g.SliceStr{"d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_UnmarshalValue(t *testing.T) {
|
||||
type V struct {
|
||||
Name string
|
||||
@ -777,6 +788,20 @@ func TestSortedStrArray_UnmarshalValue(t *testing.T) {
|
||||
t.Assert(v.Array.Slice(), g.SliceStr{"1", "2", "3"})
|
||||
})
|
||||
}
|
||||
func TestSortedStrArray_Filter(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewSortedStrArrayFrom(g.SliceStr{"", "1", "2", "0"})
|
||||
t.Assert(array.Filter(func(index int, value string) bool {
|
||||
return empty.IsEmpty(value)
|
||||
}), g.SliceStr{"0", "1", "2"})
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewSortedStrArrayFrom(g.SliceStr{"1", "2"})
|
||||
t.Assert(array.Filter(func(index int, value string) bool {
|
||||
return empty.IsEmpty(value)
|
||||
}), g.SliceStr{"1", "2"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_FilterEmpty(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
|
||||
@ -407,7 +407,6 @@ func (l *List) Removes(es []*Element) {
|
||||
for _, e := range es {
|
||||
l.list.Remove(e)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RemoveAll removes all elements from list `l`.
|
||||
|
||||
@ -157,7 +157,7 @@ func (m *AnyAnyMap) Search(key interface{}) (value interface{}, found bool) {
|
||||
func (m *AnyAnyMap) Get(key interface{}) (value interface{}) {
|
||||
m.mu.RLock()
|
||||
if m.data != nil {
|
||||
value, _ = m.data[key]
|
||||
value = m.data[key]
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
return
|
||||
@ -514,3 +514,24 @@ func (m *AnyAnyMap) DeepCopy() interface{} {
|
||||
}
|
||||
return NewFrom(data, m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// IsSubOf checks whether the current map is a sub-map of `other`.
|
||||
func (m *AnyAnyMap) IsSubOf(other *AnyAnyMap) bool {
|
||||
if m == other {
|
||||
return true
|
||||
}
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key, value := range m.data {
|
||||
otherValue, ok := other.data[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if otherValue != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// IntAnyMap implements map[int]interface{} with RWMutex that has switch.
|
||||
type IntAnyMap struct {
|
||||
mu rwmutex.RWMutex
|
||||
data map[int]interface{}
|
||||
@ -157,7 +158,7 @@ func (m *IntAnyMap) Search(key int) (value interface{}, found bool) {
|
||||
func (m *IntAnyMap) Get(key int) (value interface{}) {
|
||||
m.mu.RLock()
|
||||
if m.data != nil {
|
||||
value, _ = m.data[key]
|
||||
value = m.data[key]
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
return
|
||||
@ -514,3 +515,24 @@ func (m *IntAnyMap) DeepCopy() interface{} {
|
||||
}
|
||||
return NewIntAnyMapFrom(data, m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// IsSubOf checks whether the current map is a sub-map of `other`.
|
||||
func (m *IntAnyMap) IsSubOf(other *IntAnyMap) bool {
|
||||
if m == other {
|
||||
return true
|
||||
}
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key, value := range m.data {
|
||||
otherValue, ok := other.data[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if otherValue != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// IntIntMap implements map[int]int with RWMutex that has switch.
|
||||
type IntIntMap struct {
|
||||
mu rwmutex.RWMutex
|
||||
data map[int]int
|
||||
@ -143,7 +144,7 @@ func (m *IntIntMap) Search(key int) (value int, found bool) {
|
||||
func (m *IntIntMap) Get(key int) (value int) {
|
||||
m.mu.RLock()
|
||||
if m.data != nil {
|
||||
value, _ = m.data[key]
|
||||
value = m.data[key]
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
return
|
||||
@ -484,3 +485,24 @@ func (m *IntIntMap) DeepCopy() interface{} {
|
||||
}
|
||||
return NewIntIntMapFrom(data, m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// IsSubOf checks whether the current map is a sub-map of `other`.
|
||||
func (m *IntIntMap) IsSubOf(other *IntIntMap) bool {
|
||||
if m == other {
|
||||
return true
|
||||
}
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key, value := range m.data {
|
||||
otherValue, ok := other.data[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if otherValue != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// IntStrMap implements map[int]string with RWMutex that has switch.
|
||||
type IntStrMap struct {
|
||||
mu rwmutex.RWMutex
|
||||
data map[int]string
|
||||
@ -143,7 +144,7 @@ func (m *IntStrMap) Search(key int) (value string, found bool) {
|
||||
func (m *IntStrMap) Get(key int) (value string) {
|
||||
m.mu.RLock()
|
||||
if m.data != nil {
|
||||
value, _ = m.data[key]
|
||||
value = m.data[key]
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
return
|
||||
@ -484,3 +485,24 @@ func (m *IntStrMap) DeepCopy() interface{} {
|
||||
}
|
||||
return NewIntStrMapFrom(data, m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// IsSubOf checks whether the current map is a sub-map of `other`.
|
||||
func (m *IntStrMap) IsSubOf(other *IntStrMap) bool {
|
||||
if m == other {
|
||||
return true
|
||||
}
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key, value := range m.data {
|
||||
otherValue, ok := other.data[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if otherValue != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -152,7 +152,7 @@ func (m *StrAnyMap) Search(key string) (value interface{}, found bool) {
|
||||
func (m *StrAnyMap) Get(key string) (value interface{}) {
|
||||
m.mu.RLock()
|
||||
if m.data != nil {
|
||||
value, _ = m.data[key]
|
||||
value = m.data[key]
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
return
|
||||
@ -501,3 +501,24 @@ func (m *StrAnyMap) DeepCopy() interface{} {
|
||||
}
|
||||
return NewStrAnyMapFrom(data, m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// IsSubOf checks whether the current map is a sub-map of `other`.
|
||||
func (m *StrAnyMap) IsSubOf(other *StrAnyMap) bool {
|
||||
if m == other {
|
||||
return true
|
||||
}
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key, value := range m.data {
|
||||
otherValue, ok := other.data[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if otherValue != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// StrIntMap implements map[string]int with RWMutex that has switch.
|
||||
type StrIntMap struct {
|
||||
mu rwmutex.RWMutex
|
||||
data map[string]int
|
||||
@ -144,7 +145,7 @@ func (m *StrIntMap) Search(key string) (value int, found bool) {
|
||||
func (m *StrIntMap) Get(key string) (value int) {
|
||||
m.mu.RLock()
|
||||
if m.data != nil {
|
||||
value, _ = m.data[key]
|
||||
value = m.data[key]
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
return
|
||||
@ -488,3 +489,24 @@ func (m *StrIntMap) DeepCopy() interface{} {
|
||||
}
|
||||
return NewStrIntMapFrom(data, m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// IsSubOf checks whether the current map is a sub-map of `other`.
|
||||
func (m *StrIntMap) IsSubOf(other *StrIntMap) bool {
|
||||
if m == other {
|
||||
return true
|
||||
}
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key, value := range m.data {
|
||||
otherValue, ok := other.data[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if otherValue != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// StrStrMap implements map[string]string with RWMutex that has switch.
|
||||
type StrStrMap struct {
|
||||
mu rwmutex.RWMutex
|
||||
data map[string]string
|
||||
@ -144,7 +145,7 @@ func (m *StrStrMap) Search(key string) (value string, found bool) {
|
||||
func (m *StrStrMap) Get(key string) (value string) {
|
||||
m.mu.RLock()
|
||||
if m.data != nil {
|
||||
value, _ = m.data[key]
|
||||
value = m.data[key]
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
return
|
||||
@ -477,3 +478,24 @@ func (m *StrStrMap) DeepCopy() interface{} {
|
||||
}
|
||||
return NewStrStrMapFrom(data, m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// IsSubOf checks whether the current map is a sub-map of `other`.
|
||||
func (m *StrStrMap) IsSubOf(other *StrStrMap) bool {
|
||||
if m == other {
|
||||
return true
|
||||
}
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key, value := range m.data {
|
||||
otherValue, ok := other.data[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if otherValue != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -101,6 +101,7 @@ func Test_Map_Basic(t *testing.T) {
|
||||
t.Assert(m2.Map(), map[interface{}]interface{}{1: 1, "key1": "val1"})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Map_Set_Fun(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.New()
|
||||
@ -123,6 +124,7 @@ func Test_Map_Batch(t *testing.T) {
|
||||
t.Assert(m.Map(), map[interface{}]interface{}{"key2": "val2", "key3": "val3"})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Map_Iterator(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
expect := map[interface{}]interface{}{1: 1, "key1": "val1"}
|
||||
@ -175,6 +177,7 @@ func Test_Map_Clone(t *testing.T) {
|
||||
t.AssertIN("key1", m.Keys())
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Map_Basic_Merge(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.New()
|
||||
|
||||
@ -16,7 +16,9 @@ import (
|
||||
)
|
||||
|
||||
var hashMap = gmap.New(true)
|
||||
|
||||
var listMap = gmap.NewListMap(true)
|
||||
|
||||
var treeMap = gmap.NewTreeMap(gutil.ComparatorInt, true)
|
||||
|
||||
func Benchmark_HashMap_Set(b *testing.B) {
|
||||
|
||||
@ -16,11 +16,17 @@ import (
|
||||
)
|
||||
|
||||
var anyAnyMap = gmap.NewAnyAnyMap(true)
|
||||
|
||||
var intIntMap = gmap.NewIntIntMap(true)
|
||||
|
||||
var intAnyMap = gmap.NewIntAnyMap(true)
|
||||
|
||||
var intStrMap = gmap.NewIntStrMap(true)
|
||||
|
||||
var strIntMap = gmap.NewStrIntMap(true)
|
||||
|
||||
var strAnyMap = gmap.NewStrAnyMap(true)
|
||||
|
||||
var strStrMap = gmap.NewStrStrMap(true)
|
||||
|
||||
func Benchmark_IntIntMap_Set(b *testing.B) {
|
||||
|
||||
@ -16,6 +16,7 @@ import (
|
||||
)
|
||||
|
||||
var gm = gmap.NewIntIntMap(true)
|
||||
|
||||
var sm = sync.Map{}
|
||||
|
||||
func Benchmark_GMapSet(b *testing.B) {
|
||||
|
||||
@ -16,11 +16,17 @@ import (
|
||||
)
|
||||
|
||||
var anyAnyMapUnsafe = gmap.New()
|
||||
|
||||
var intIntMapUnsafe = gmap.NewIntIntMap()
|
||||
|
||||
var intAnyMapUnsafe = gmap.NewIntAnyMap()
|
||||
|
||||
var intStrMapUnsafe = gmap.NewIntStrMap()
|
||||
|
||||
var strIntMapUnsafe = gmap.NewStrIntMap()
|
||||
|
||||
var strAnyMapUnsafe = gmap.NewStrAnyMap()
|
||||
|
||||
var strStrMapUnsafe = gmap.NewStrStrMap()
|
||||
|
||||
// Writing benchmarks.
|
||||
|
||||
@ -8,11 +8,11 @@ package gmap_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
func ExampleAnyAnyMap_Iterator() {
|
||||
|
||||
@ -8,6 +8,7 @@ package gmap_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
|
||||
@ -8,6 +8,7 @@ package gmap_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
|
||||
@ -8,11 +8,11 @@ package gmap_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
func ExampleStrAnyMap_Iterator() {
|
||||
|
||||
@ -8,6 +8,7 @@ package gmap_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
|
||||
@ -8,12 +8,11 @@ package gmap_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
func ExampleStrStrMap_Iterator() {
|
||||
|
||||
@ -9,9 +9,8 @@ package gmap_test
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
)
|
||||
|
||||
func ExampleNew() {
|
||||
|
||||
@ -391,3 +391,18 @@ func Test_AnyAnyMap_DeepCopy(t *testing.T) {
|
||||
t.AssertNE(m.Get("k1"), n.Get("k1"))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_IsSubOf(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewAnyAnyMapFrom(g.MapAnyAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
})
|
||||
m2 := gmap.NewAnyAnyMapFrom(g.MapAnyAny{
|
||||
"k2": "v2",
|
||||
})
|
||||
t.Assert(m1.IsSubOf(m2), false)
|
||||
t.Assert(m2.IsSubOf(m1), true)
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -117,6 +117,7 @@ func Test_IntAnyMap_Batch(t *testing.T) {
|
||||
t.Assert(m.Map(), map[int]interface{}{3: 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntAnyMap_Iterator(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
expect := map[int]interface{}{1: 1, 2: "2"}
|
||||
@ -154,6 +155,7 @@ func Test_IntAnyMap_Lock(t *testing.T) {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntAnyMap_Clone(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// clone 方法是深克隆
|
||||
@ -169,6 +171,7 @@ func Test_IntAnyMap_Clone(t *testing.T) {
|
||||
t.AssertIN(2, m.Keys())
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntAnyMap_Merge(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewIntAnyMap()
|
||||
@ -372,3 +375,18 @@ func Test_IntAnyMap_DeepCopy(t *testing.T) {
|
||||
t.AssertNE(m.Get(1), n.Get(1))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntAnyMap_IsSubOf(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewIntAnyMapFrom(g.MapIntAny{
|
||||
1: "v1",
|
||||
2: "v2",
|
||||
})
|
||||
m2 := gmap.NewIntAnyMapFrom(g.MapIntAny{
|
||||
2: "v2",
|
||||
})
|
||||
t.Assert(m1.IsSubOf(m2), false)
|
||||
t.Assert(m2.IsSubOf(m1), true)
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -383,3 +383,18 @@ func Test_IntIntMap_DeepCopy(t *testing.T) {
|
||||
t.AssertNE(m.Get(1), n.Get(1))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntIntMap_IsSubOf(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewIntAnyMapFrom(g.MapIntAny{
|
||||
1: 1,
|
||||
2: 2,
|
||||
})
|
||||
m2 := gmap.NewIntAnyMapFrom(g.MapIntAny{
|
||||
2: 2,
|
||||
})
|
||||
t.Assert(m1.IsSubOf(m2), false)
|
||||
t.Assert(m2.IsSubOf(m1), true)
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -152,6 +152,7 @@ func Test_IntStrMap_Batch(t *testing.T) {
|
||||
t.Assert(m.Map(), map[int]interface{}{3: "c"})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntStrMap_Iterator(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
expect := map[int]string{1: "a", 2: "b"}
|
||||
@ -204,6 +205,7 @@ func Test_IntStrMap_Clone(t *testing.T) {
|
||||
t.AssertIN(2, m.Keys())
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntStrMap_Merge(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewIntStrMap()
|
||||
@ -445,3 +447,18 @@ func Test_IntStrMap_DeepCopy(t *testing.T) {
|
||||
t.AssertNE(m.Get(1), n.Get(1))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntStrMap_IsSubOf(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewIntStrMapFrom(g.MapIntStr{
|
||||
1: "v1",
|
||||
2: "v2",
|
||||
})
|
||||
m2 := gmap.NewIntStrMapFrom(g.MapIntStr{
|
||||
2: "v2",
|
||||
})
|
||||
t.Assert(m1.IsSubOf(m2), false)
|
||||
t.Assert(m2.IsSubOf(m1), true)
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -146,6 +146,7 @@ func Test_StrAnyMap_Lock(t *testing.T) {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrAnyMap_Clone(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// clone 方法是深克隆
|
||||
@ -161,6 +162,7 @@ func Test_StrAnyMap_Clone(t *testing.T) {
|
||||
t.AssertIN("b", m.Keys())
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrAnyMap_Merge(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewStrAnyMap()
|
||||
@ -379,3 +381,18 @@ func Test_StrAnyMap_DeepCopy(t *testing.T) {
|
||||
t.AssertNE(m.Get("key1"), n.Get("key1"))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrAnyMap_IsSubOf(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewStrAnyMapFrom(g.MapStrAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
})
|
||||
m2 := gmap.NewStrAnyMapFrom(g.MapStrAny{
|
||||
"k2": "v2",
|
||||
})
|
||||
t.Assert(m1.IsSubOf(m2), false)
|
||||
t.Assert(m2.IsSubOf(m1), true)
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -117,6 +117,7 @@ func Test_StrIntMap_Batch(t *testing.T) {
|
||||
t.Assert(m.Map(), map[string]int{"c": 3})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrIntMap_Iterator(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
expect := map[string]int{"a": 1, "b": 2}
|
||||
@ -170,6 +171,7 @@ func Test_StrIntMap_Clone(t *testing.T) {
|
||||
t.AssertIN("b", m.Keys())
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrIntMap_Merge(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewStrIntMap()
|
||||
@ -387,3 +389,18 @@ func Test_StrIntMap_DeepCopy(t *testing.T) {
|
||||
t.AssertNE(m.Get("key1"), n.Get("key1"))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrIntMap_IsSubOf(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewStrIntMapFrom(g.MapStrInt{
|
||||
"k1": 1,
|
||||
"k2": 2,
|
||||
})
|
||||
m2 := gmap.NewStrIntMapFrom(g.MapStrInt{
|
||||
"k2": 2,
|
||||
})
|
||||
t.Assert(m1.IsSubOf(m2), false)
|
||||
t.Assert(m2.IsSubOf(m1), true)
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -116,6 +116,7 @@ func Test_StrStrMap_Batch(t *testing.T) {
|
||||
t.Assert(m.Map(), map[string]string{"c": "c"})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrStrMap_Iterator(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
expect := map[string]string{"a": "a", "b": "b"}
|
||||
@ -153,6 +154,7 @@ func Test_StrStrMap_Lock(t *testing.T) {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrStrMap_Clone(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// clone 方法是深克隆
|
||||
@ -168,6 +170,7 @@ func Test_StrStrMap_Clone(t *testing.T) {
|
||||
t.AssertIN("b", m.Keys())
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrStrMap_Merge(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewStrStrMap()
|
||||
@ -385,3 +388,18 @@ func Test_StrStrMap_DeepCopy(t *testing.T) {
|
||||
t.AssertNE(m.Get("key1"), n.Get("key1"))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrStrMap_IsSubOf(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewStrStrMapFrom(g.MapStrStr{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
})
|
||||
m2 := gmap.NewStrStrMapFrom(g.MapStrStr{
|
||||
"k2": "v2",
|
||||
})
|
||||
t.Assert(m1.IsSubOf(m2), false)
|
||||
t.Assert(m2.IsSubOf(m1), true)
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -106,6 +106,7 @@ func Test_ListMap_Batch(t *testing.T) {
|
||||
t.Assert(m.Map(), map[interface{}]interface{}{"key2": "val2", "key3": "val3"})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ListMap_Iterator(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
expect := map[interface{}]interface{}{1: 1, "key1": "val1"}
|
||||
|
||||
@ -107,6 +107,7 @@ func Test_TreeMap_Batch(t *testing.T) {
|
||||
t.Assert(m.Map(), map[interface{}]interface{}{"key2": "val2", "key3": "val3"})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_TreeMap_Iterator(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
expect := map[interface{}]interface{}{1: 1, "key1": "val1"}
|
||||
|
||||
@ -84,6 +84,13 @@ func (p *Pool) Put(value interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MustPut puts an item to pool, it panics if any error occurs.
|
||||
func (p *Pool) MustPut(value interface{}) {
|
||||
if err := p.Put(value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Clear clears pool, which means it will remove all items from pool.
|
||||
func (p *Pool) Clear() {
|
||||
if p.ExpireFunc != nil {
|
||||
@ -97,7 +104,6 @@ func (p *Pool) Clear() {
|
||||
} else {
|
||||
p.list.RemoveAll()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Get picks and returns an item from pool. If the pool is empty and NewFunc is defined,
|
||||
|
||||
@ -17,6 +17,7 @@ import (
|
||||
)
|
||||
|
||||
var pool = gpool.New(time.Hour, nil)
|
||||
|
||||
var syncp = sync.Pool{}
|
||||
|
||||
func BenchmarkGPoolPut(b *testing.B) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user