使用golang开发项目demo

使用go语言开发项目的现状

很多公司都是使用go语言来开发程序,但是开发中以及最终交付的代码需要满足以下条件:

  • 能满足DevOps要求,对于开发来说,需要提供一个构建脚本(build.sh)即可
  • 内网也能编译,即build.sh能执行的环境属于内网,不能直接下载第三方库
  • 能在流水线上跑,但是流水线所在的服务器对于权限要求很高,不能随意更改/etc/profile等相关配置文件
  • 代码管控使用git,构建出来的可执行文件内部必须有git信息、版本号、构建日期等信息
  • 写代码的工具使用golandgoland方便调试,goland再使用上也有不少的坑
  • 构建出来的可执行文件有多个,即有多个main函数

golangSDK

国外网址可能不行,直接从以下网址下载即可

https://www.gomirrors.org

下载的时候需要注意以下几点:

  • 尽量自己从网上下载的,不要使用apt-getbrew下载,因为路径不一样,假如出现问题了,排查起来很麻烦,虽然我本人没有遇到此问题
  • 有些goland不能识别高版本的golang
  • 注意GOMODULE所支持的版本,目前的开发大部分都需要支持此特性

本人使用的是Mac,使用的是brew安装,下面是我本机的信息

# 查看go的路径
fh@Feihu-3 go % which go
/usr/local/bin/go

# 实际上,这是一个软连接
fh@Feihu-3 go % ls -l /usr/local/bin/go
lrwxr-xr-x  1 fh  admin  26  8 22 16:01 /usr/local/bin/go -> ../Cellar/go/1.16.6/bin/go
fh@Feihu-3 go %
# 这些信息是没有修改过的
# 如果修改过的环境变量,存放的路径是GOENV中
# 修改命令,eg:
# go env -w GO111MODULE=on
fh@Feihu-3 go % go env
GO111MODULE=""    # 模块管理,注意此项
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/fh/Library/Caches/go-build"
GOENV="/Users/fh/Library/Application Support/go/env" # 当前变更的记录环境变量路径
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/fh/go/pkg/mod" # 下载的第三方包的路径
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/fh/go" # GOPATH,视情况而定
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct" # 从某个域名去下载第三方包,一定修改
GOROOT="/usr/local/Cellar/go/1.16.6/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.16.6/libexec/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.16.6"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/8m/dwtpjrx55ks5tbh3x08ln6wh0000gn/T/go-build60378254=/tmp/go-build -gno-record-gcc-switches -fno-common"

# 没有设置网络上的GOROOT、GOPATH等环境变量
fh@Feihu-3 go % echo $GOROOT

fh@Feihu-3 go % echo $GOPATH

fh@Feihu-3 go %

综上,我们需要在build.sh或者goland内部配置这些参数:

GO111MODULE # 当前使用go.mod,配置为on
GOMODCACHE  # 修改,否则会从默认的去找 
GOPROXY     # 必须修改,否则下载会遇到问题
GOPATH			# 当前使用go.mod,不修改

代码结构

使用tree命令,获得代码结构如下:

本人喜欢人民币,所以取的项目,名称叫做RMB

fh@Feihu-3 RMB % tree
.
├── build
│   └── darwin
│       └── amd64
│           └── bin
│               ├── dn
│               ├── glog_demo
│               └── meta
├── pkg
│   └── mod
│       ├── cache
│       │   └── download
│       │       └── github.com
│       │           └── golang
│       │               └── glog
│       │                   └── @v
│       │                       ├── list
│       │                       ├── list.lock
│       │                       ├── v1.0.0.info
│       │                       ├── v1.0.0.lock
│       │                       ├── v1.0.0.mod
│       │                       ├── v1.0.0.zip
│       │                       └── v1.0.0.ziphash
│       └── github.com
│           └── golang
│               └── glog@v1.0.0
│                   ├── LICENSE
│                   ├── README.md
│                   ├── glog.go
│                   ├── glog_file.go
│                   ├── glog_test.go
│                   └── go.mod
└── src
    ├── base
    │   └── log
    │       └── log.go
    ├── build.sh
    ├── cmd
    │   ├── demo
    │   │   └── glog_demo.go
    │   └── server
    │       ├── dn.go
    │       ├── meta.go
    │       └── version.go
    ├── go.mod
    └── go.sum

21 directories, 24 files

对于这一套RMB的代码分为以下几个方面:

# RMB下分为三个目录:
# src:存放自己编写的代码
# pkg: 第三方包
# build:生成的可执行文件

# 其中功能如下:
# 1. 调用glog第三方库,编写glog_demo,路径是RMB/build/darwin/amd64/bin/glog_demo
# 2. 生成meta可执行文件,路径是RMB/build/darwin/amd64/bin/meta
# 3. 生成dn可执行文件,路径是RMB/build/darwin/amd64/bin/dn
# 4. 在编译的时候,自动将git的信息、构建日期等传递到可执行文件中
# 5. 封装go语言的log,并测试

开发流程

建立RMB文件夹

RMB下初始化模块

RMB目录下,执行go init rmb命令,生成go.mod文件,go.mod生成之后,不用我们自己管了,后续执行build的时候会自动维护go.mod以及go.sum

编写main函数文件以及build.sh

编写几个main函数入口,能够执行即可,方便build.sh验证

# version.go隶属于main包
# meta.go、dn.go和version必须要放到同一个目录下
# 同一个包调用不同文件问题,后面继续说
fh@Feihu-3 RMB % ls src/cmd/server/*
src/cmd/server/dn.go		src/cmd/server/meta.go		src/cmd/server/version.go
#! /bin/bash

# 执行的命令中,返回非0错误码即退出,不再执行后面内容
set -e

# 增加调试信息,执行的时候会打印所有的信息,真实环境会注释掉
set -x

# build.sh放在src目录下,获取RMB/src的路径
PROJ_SRC="$(cd "$(dirname "$0")"; pwd -P)"

# src目录的上级就是RMB路径
PROJ_ROOT="$(cd "$(dirname "$PROJ_SRC")"; pwd -P)"

# build路径: RMB/build
PROJ_BUILD=${PROJ_ROOT}/build

# 环境变量设置,通过go env GOROOT获取
export GOROOT=$(go env GOROOT)

# 下载包路径,默认是下载失败的,主要是给go get使用
export GOPROXY=https://goproxy.io

# 下载的第三方包路径,并自动从这里查找
export GOMODCACHE=${PROJ_ROOT}/pkg/mod

# 开启模块
export GO111MODULE="on"

# 清空RMB/build目录
rm -rf "${PROJ_BUILD}"
mkdir -p "${PROJ_BUILD}"

# 代码格式化,例如:Tab、大括号等格式
# 帮助可查gofmt -h
gofmt -l -w -s "${PROJ_SRC}"

# 标记,通过脚本将这些信息扔到代码里面去
# 这段代码来自etcd的Makefile,并加以修改,其实也只是version.go里面传参数
# 内容是:软件版本、GO系统、GO架构、git的提交、构建日期、go版本、构建者
# 由于本人未使用git,请将gitCommit的值换成下面提到的命令即可
LD_FLAGS=" \
    -X main.rmbBuilderVersion='1.3.2' \
    -X main.goos=$(go env GOOS) \
    -X main.goarch=$(go env GOARCH) \
    -X main.gitCommit='adfjlkdf' \
    -X main.buildDate=$(date +'%Y-%m-%dT%H:%M:%SZ') \
    -X main.goversion=$(go env GOVERSION) \
    -X main.builder=$(whoami) \
    "

# -o: 生成的可执行文件路径,RMB/build/darwin/amd64/bin/meta
# -a: 强制重新构建包
# -race: 	开启数据竞态检测
# 注意: go build的最后一项是main函数所在的文件以及version文件
# 不增加version.go会失败,因为version.go里面的符号未提前生成,导致查询失败
go build -o "${PROJ_BUILD}"/$(go env GOHOSTOS)/$(go env GOHOSTARCH)/bin/meta \
         -a \
         -race \
         -ldflags "-X main.buildDate=$(date +'%Y-%m-%dT%H:%M:%SZ') \
                   -X main.goos=$(go env GOOS) \
                   -X main.goarch=$(go env GOARCH) \
                  " \
         "${PROJ_SRC}"/cmd/server/version.go "${PROJ_SRC}"/cmd/server/meta.go

go build -o "${PROJ_BUILD}"/$(go env GOHOSTOS)/$(go env GOHOSTARCH)/bin/dn \
         -a \
         -race \
         -ldflags "${LD_FLAGS}" \
         "${PROJ_SRC}"/cmd/server/version.go "${PROJ_SRC}"/cmd/server/dn.go

go build -o "${PROJ_BUILD}"/$(go env GOHOSTOS)/$(go env GOHOSTARCH)/bin/glog_demo \
         -a \
         -race \
         "${PROJ_SRC}"/cmd/demo/glog_demo.go
LD_FLAGS=-ldflags " \
    -X main.kubeBuilderVersion=$(shell git describe --tags --dirty --broken) \
    -X main.goos=$(shell go env GOOS) \
    -X main.goarch=$(shell go env GOARCH) \
    -X main.gitCommit=$(shell git rev-parse HEAD) \
    -X main.buildDate=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ') \
    "

下载第三方包

我们在配置好了之后,一般是先提前下载第三方包,再去写代码,因为我们需要有代码提示,例如:

# 下载的包路径根据GOMODCACHE 来确定
# 后面查找的时候,也是从GOMODCACHE来找
# 所以,需要在环境变量里面设置GOMODCACHE路径
go get github.com/golang/glog

至于下载完了之后,代码引用,可以根据我写的demo来看

package main

import (
	"flag"
	"fmt"
	"github.com/golang/glog"
)

func main() {
	flag.Parse()
	defer glog.Flush()

	glog.Info("Fish")
	glog.Infof("I like fish, value: %v", "mnkojj")

	fmt.Println("xx")
}

本工程代码的连接如下:

# 之前写的,可根据编译脚本来做调整
https://download.csdn.net/download/wfh2015/21710635

编译结果:

fh@Feihu-3 src % ./build.sh
go: downloading github.com/golang/glog v1.0.0  # 在有网却缺少库的情况,自动下载
fh@Feihu-3 src % tree ../build
../build
└── darwin
    └── amd64
        └── bin
            ├── dn
            ├── glog_demo
            └── meta

3 directories, 3 files
fh@Feihu-3 src % go mod tidy
fh@Feihu-3 src % go mod verify
all modules verified
fh@Feihu-3 src % go mod graph
rmb github.com/golang/glog@v1.0.0
fh@Feihu-3 src % go mod why
fh@Feihu-3 src %

至于其他的命令像什么,就不用说了:

go mod tidy
go mod graph
go mod verify
go mod graphv

因为设置了GOMODCACHE路径,在内网使用的时候,直接将RMB下的所有文件拷贝过去即可。

目前来看,不需要手动修改配置文件,基本满足在内网运行、DevOps运行的要求。

问题

同一个包调用不同文件的接口会报错

这个问题解决方法有两类:

# 脚本:
# 只需要将两个go文件同时放到go build 中即可,参考前面的build.sh脚本
# goland
# 1. [打开编辑配置] -> [运行种类] -> [文件]
# 2. [文件]所在行的[展开]按钮,增加多个文件,增加之后,编辑栏会有‘|’符号区分不同路径
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: golang 中可以使用 os 包中的 Walk 函数来遍历文件夹。 Walk 函数需要接收两个参数:根目录路径和一个回调函数。它会将根目录和所有子目录的文件信息都传入回调函数,你可以在回调函数中对这些文件信息进行处理。 下面是一个使用 Walk 遍历文件夹的示例: ``` package main import ( "fmt" "os" "path/filepath" ) func main() { root := "path/to/root" err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { return err } fmt.Println(path) return nil }) if err != nil { panic(err) } } ``` Walk 函数会将 root 目录下的所有文件信息都传入回调函数,你可以在回调函数中对文件进行处理。 你也可以使用 filepath.Walk 函数来遍历文件夹,它的用法和 os.Walk 函数类似。 ### 回答2: 使用Go语言遍历所有文件夹可以通过递归算法实现。具体的步骤如下: 1. 导入`os`包和`path/filepath`包。`os`包提供了操作系统相关的功能,`path/filepath`包提供了处理文件路径的方法。 2. 创建一个函数,命名为`walkDir`,用于递归遍历文件夹。该函数接收两个参数:文件夹路径和一个回调函数。 3. 在`walkDir`函数内部,使用`os.Open`打开当前文件夹,并使用`os.Readdir`读取文件夹中的所有文件和子文件夹。 4. 遍历得到的文件和子文件夹列表,通过判断是否是文件夹来确定进一步处理。如果是文件夹,则递归调用`walkDir`函数,传入子文件夹路径和回调函数。 5. 如果是文件,则将文件路径传递给回调函数进行处理。可以在回调函数中执行需要的操作,例如打印文件路径。 6. 最后,在`main`函数中调用`walkDir`函数,传入需要遍历的文件夹路径和回调函数。 下面是一个示例代码: ```go package main import ( "fmt" "os" "path/filepath" ) func walkDir(dirPath string, callback func(string)) error { fileInfos, err := os.ReadDir(dirPath) if err != nil { return err } for _, fileInfo := range fileInfos { filePath := filepath.Join(dirPath, fileInfo.Name()) if fileInfo.IsDir() { err = walkDir(filePath, callback) if err != nil { return err } } else { callback(filePath) } } return nil } func main() { dirPath := "路径/文件夹" // 替换为实际的文件夹路径 err := walkDir(dirPath, func(filePath string) { fmt.Println(filePath) }) if err != nil { fmt.Println(err) } } ``` 以上代码可以遍历指定路径下的所有文件和文件夹,并打印文件路径。可以将回调函数的逻辑替换为自己需要的操作。 ### 回答3: 在Go语言中,可以使用filepath包和os包来遍历所有文件夹。 首先,我们需要导入这两个包: ```go import ( "fmt" "os" "path/filepath" ) ``` 然后,我们可以定义一个函数来遍历文件夹,函数的参数是要遍历的文件夹路径: ```go func traverseFolders(path string) { // 使用Walk函数来遍历文件夹下的所有文件和文件夹 err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error { // 如果遍历过程中出现错误,则输出错误信息并返回错误 if err != nil { fmt.Println(err) return err } // 如果当前遍历的是文件夹,则输出文件夹路径 if info.IsDir() { fmt.Println("文件夹:", path) } return nil }) // 如果遍历过程中出现错误,则输出错误信息 if err != nil { fmt.Println(err) } } ``` 接下来,我们可以在main函数中调用这个遍历函数,并传入要遍历的文件夹路径: ```go func main() { path := "/path/to/folder" // 替换为实际的文件夹路径 traverseFolders(path) } ``` 以上就是使用Go语言遍历所有文件夹的方法。这段代码会输出所有遍历到的文件夹路径。你可以根据需要来对每个文件夹执行特定的操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值