How to resolve user environment variables in filepath - windows

Golang on windows. Trying to use
os.Open("%userprofile%\\myfile.txt")
Getting file path not found and golang is not resolving %userprofile% to my C:\users\myusername folder.

To get a file handle, and make your program a little portable too, try
userprofile := os.Getenv("USERPROFILE")
f, err := os.Open(path.Join(userprofile, "myfile.txt"))
The os.Getenv() will read the environment variable and path.Join() will take care of properly constructing the path (so no need to do \\).
Instead of os.Getenv() you might also want to look at os.LookupEnv(). This will tell you if the environment variable you're looking for is empty or simply not existing. A good example of how you can use that to set default values can be found in this answer on SO.

userprofile := os.Getenv("USERPROFILE")
os.Open(userprofile+"\\myfile.txt")

Just written a package to do this. Feedback welcome
https://gitlab.com/stu-b-doo/windowspathenv/
fmt.Println(windowspathenv.Resolve("%USERPROFILE%/Documents"))
// C:\Users\YourName\Documents

Have a look at http://www.golangprograms.com/how-to-set-get-and-list-environment-variables.html
You can read the 'userprofile' environment value and and build the path before passing it to os.Open

Related

Using paths in different packages convenient way

I have a program in which I use a lot "../" which is to go one level up
in the file system and run some process on the directory with specific name. I have a command line tool in Go.
I have 3 questions
there is nicer way to do it instead of “../“
is there a const with which I can use instead of “/“
if 2 is not available should I create “constants“ under that internal package to share the “/“ between packages since I need it in
many place (from diff packages...)
example
dir.zip("../"+tmpDirName, "../"+m.Id+".zip", "../"+tmpDirName)
Set a variable, and use that everywhere:
path := "../"
or
path := ".." + string(os.PathSeparator)
then later:
dir.zip(path+tmpDirName, path+m.Id+".zip", path+tmpDirName)
This makes it very easy to change the path in the future, via a command line option, configuration, or just editing the value.
Yes. os.PathSeparator is the OS-specific path separator for the current architecture.
n/a
declare a global const somewhere, but I would just use ".." everywhere
os.PathSeparator
use filepath.Join("..", someDir, someFilename)

How can I resolve a relative path to absolute path in golang?

Is there a api like 'path.resolve' in node? Or something can do the same?
For Example (nodejs code):
path.resolve("~/sample.sh")
Should got: /home/currentuser/sample.sh
Resolving ~ (denoting the user home) is a different story, and usually it's the shell that resolves this. For details see Expand tilde to home directory.
If you want to do it from Go code, you may use the user.Current() function to get details about the current user, including its home folder which will be User.HomeDir. But still, you'll have to handle replacing this yourself.
Original answer follows.
You may use path.Join() or filepath.Join().
For example:
base := "/home/bob"
fmt.Println(path.Join(base, "work/go", "src/github.com"))
Output:
/home/bob/work/go/src/github.com
You may use path.Clean() and filepath.Clean() to "remove" dots . and double dots .. from your path.
You may use filepath.Abs() to resolve relative paths and get an absolute (prepending the working directory if it's not absolute). filepath.Abs() also calls Clean() on the result.
For example:
fmt.Println(filepath.Abs("/home/bob/../alice"))
Outputs:
/home/alice <nil>
Try the examples on the Go Playground.
See related question: Resolving absolute path from relative path

Read file from relative path with different callers

I'm trying to read from a file in my project's directory.
My problem is, that depending on the caller, the path changes. The caller changes, because I want to unit test this code and the caller is not Main.go anymore.
This is what my project structure looks like:
The code where I try to access specialChars.txt from looks like this:
func RemoveSpecialChars(word string) string {
file, err := ioutil.ReadFile("wordlists/specialChars.txt")
[...]
}
This code works for the start from Main.go but not for the start from CleanupUtil_test.go. To get it working from the test I would need file, err := ioutil.ReadFile("../wordlists/specialChars.txt")
I found answers like this one: https://stackoverflow.com/a/32163888/2837489
_, filename, _, ok := runtime.Caller(0) which is obviously also dependent on the caller.
Is it possible to get the projects root path independent of the calling function?
Or is my code design wrong? Should I pass the file path into the function?
Starting from Go 1.16, you can use the embed package. This allows you to embed the files in the running go program. It comes with the caveat that the referenced directory needs to exist at or below the embedding file. In your case, the structure would look as follows:
-- main.go
-- cleanup
-- wordlist
\- specialChars.txt
CleanupUtil.go
CleanupUtil_test.go
You can reference the file using a go directive
// CleanupUtil.go
package cleanup
import (
"embed"
)
//go:embed wordlists/specialChars.txt
var content embed.FS
func RemoveSpecialChars(word string) string {
file, err := content.ReadFile("wordlists/specialChars.txt")
[...]
}
This program will run successfully regardless of where the program is executed. You should be able to reference this code in both your main.go file and your CleanupUtil_test.go file.
Pass in the filepath as a parameter to the function (as indicated in your last question).
More details:
The relative path "wordlists/specialChars.txt" is in fact not dependent on where the source file is located (such as Main.go or CleanupUtil_test.go), but where you execute it from. So you could run your tests from your root directory and then it would actually work. In short, the current working directory is relevant.
Still, I'd recommend specifying the path, because that makes your function more reusable and universal.
Maybe you don't even need to put this information into a file, but can simply have a string containing those chars. In this case you could also check if https://golang.org/pkg/regexp/#Regexp.ReplaceAll already covers your use case.

how can I get the parent path base on an environment variable

I have a environment variable admin_path=/home/myfolder/server. now I need to get the parent path base on the $admin_path in shell script. how can I get it easily? thank you
It's not entirely clear what you want, but I think you are looking for:
${admin_path%/*}
to get the value of admin_path with the trailing path component removed.

Dealing with ini Files - Add Enivornment Variable

i am trying to add an evironment variable to a path inside an ini file, the variable is the current username in Windows which can be accessed via %username%.
so i would like to do path = c:\users\[username variable]\ ...
Will appreciate anyhelp
Use ExpandEnvironmentStrings().
See WritePrivateProfileString() and friends...

Resources