A chat, Golang "relative" path problem

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

Objective

GolangThere are various modes of operation, and how to properly refer to the file path becomes a question worthy of deliberation.

Take Gin-blog as an example, when we are at the root of the project, we go run main.go can run normally ( go build also normal)

[$ gin-blog]# go run main.go[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env:    export GIN_MODE=release - using code:    gin.SetMode(gin.ReleaseMode)[GIN-debug] GET    /api/v1/tags              --> gin-blog/routers/api/v1.GetTags (3 handlers)...

So at different levels of the directory, different ways to run, and what kind of, with our questions to learn

Problem

    1. Go run

We move up the directory level, go $GOPATH/src down, executego run gin-blog/main.go

[$ src]# go run gin-blog/main.go2018/03/12 16:06:13 Fail to parse 'conf/app.ini': open conf/app.ini: no such file or directoryexit status 1
    1. Go build, execute./gin-blog/main
[$ src]# ./gin-blog/main2018/03/12 16:49:35 Fail to parse 'conf/app.ini': open conf/app.ini: no such file or directory

At this time you have to hit a big question mark, that's where my program reads.

We learned from the analysis that Golang the relative path is relative to the directory when the command was executed ;

Thinking

Now that we know where the problem is, we can think about doing something:)

We think that the relative path is relative to the execution of the command directory, then we get the address of the executable file, splicing together is not good?

Practice

We write a method to get the path of the current executable file

import (    "path/filepath"    "os"    "os/exec"    "string")func GetAppPath() string {    file, _ := exec.LookPath(os.Args[0])    path, _ := filepath.Abs(file)    index := strings.LastIndex(path, string(os.PathSeparator))    return path[:index]}

Place it at the startup code to view the path

log.Println(GetAppPath())

We perform the following two commands separately to view the output results

    1. Go run
$ go run main.go2018/03/12 18:45:40 /tmp/go-build962610262/b001/exe
    1. Go Build
$ ./main2018/03/12 18:49:44 $GOPATH/src/gin-blog

Analysis

We focused on go run the output and found it to be the address of a temporary file, which is why?

In go help run , we can see

Run compiles and runs the main package comprising the named Go source files.A Go source file is defined to be a file ending in a literal ".go" suffix.

go runthat is, execution will put the file in the /tmp/go-build... directory, compile and run

So go run main.go the /tmp/go-build962610262/b001/exe result is not surprising, because it has run to the temp directory to execute the executable file.

That's clear enough, so let's think about what's going to happen.

    • A path error occurs when a file that relies on a relative path
    • go runand go build not the same, one to the temporary directory execution, one can be manually executed in the compiled directory, the path will be handled differently
    • Constantly go run , constantly generating new temporary files

This is the root cause , because go run and go build the compilation of file execution path and different, the level of execution may not be the same, naturally there are a variety of strange problems to read

Solution Solutions

One, get the compiled executable file path

    1. Stitching the relative path of a configuration file with GetAppPath() the results of an executable file that can be resolved go build main.go across directories (such as: ./src/gin-blog/main )
import (    "path/filepath"    "os"    "os/exec"    "string")func GetAppPath() string {    file, _ := exec.LookPath(os.Args[0])    path, _ := filepath.Abs(file)    index := strings.LastIndex(path, string(os.PathSeparator))    return path[:index]}

But this way, for the go run still ineffective, this time need to remedy

    1. Issues that can be resolved by specifying a path by passing parameters go run
package mainimport (    "flag"    "fmt")func main() {    var appPath string    flag.StringVar(&appPath, "app-path", "app-path")    flag.Parse()    fmt.Printf("App path: %s", appPath)}

Run

go run main.go --app-path "Your project address"

Second, increase os.Getwd() the multi-layered judgment

See code read app.conf by Beego

The notation is compatible go build and executes at the project root go run , but go run not if it is executed across directories

Third, configure global system variables

We can os.Getenv get the system global variables and then stitch them with the relative paths.

    1. Set up a project workspace

In short, it is to set the project (application) work path, and then with the configuration files, log files and other relative paths to the relative absolute path to ensure that the path is consistent

See Gogs reading GOGS_WORK_DIR the code for stitching

    1. Using the system's own variables

In simple terms, the system comes with a global variable, for example $HOME , to store the configuration file $HOME/conf or /etc/conf

This way, you can store the configuration file more fixed, without having to set an environment variable .

(This morning with a sfer discussed a wave, thanks)

Expand

go testIn some scenarios you will also encounter path problems, because go test only the current directory can be executed, so when executing the test case, your execution directory is already a test directory

It will produce a similar problem.

Summary

These three solutions can be found in open source projects or presentations that are currently visible.

The pros and cons are also obvious, and I think the right solution should be selected for different projects .

What do you think, in SF, to discuss a wave?

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.