Binary and additional files - go

I'm trying to package my go application binary which is accessible by a web interface running on localhost:8080 so that when downloaded it's able to find the JS(front-end) files in the folder where the file is ran but i can't seem to make it work.
I've been doing something like this :
pwd, err := os.Getwd()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
Then trying to use the working directory of the binary to access the files inside it but that doesn't seem to work.
The binary is located at :
/Users/admin/Desktop/testappfolder
but when i run the program with just :
pwd, err := os.Getwd()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(pwd)
I end up getting /Users/admin as the working directory instead.
I wondering :
Where i'm going wrong ?
Is this has something to do with the Gopath ?
Am i going at it the right way regarding distributing the app as a "zip" and having file path setup directly inside my program relative to the working directory ? or is it that logic that's wrong ?

os.Getwd is going to correspond to where you start your binary from not where the binary is located.
To make for a more robust solution I would pass in the location of the files directory using a flag or using a config value.

Related

Open a Word process by invoking a .docx

As in the title, I need to open a Word process by invoking via a .docx file. Using cmd, I can type test.docx and the file is then open in Word immediately. However, if I use
cmd := exec.Command(`test.docx`)
err := cmd.Start()
if err != nil {
log.Fatalln(err)
}
The word process is not started. Instead, I receive an error:
fork/exec .\test.docx: %1 is not a valid Win32 application.
I've also tried
cmd := exec.Command(`cmd.exe`, `\C`, `start`, `.\test.docx`)
but it doesn't work, either.
Is there anyway to do this? I'd be very appreciated for any help
I've investigate a little bit more and have found a solution, using PowerShell instead. However, this is only valid for systems that have PowerShell (of course)
cmd_instance := exec.Command("powershell.exe", "Start-Process", "-FilePath", `.\test.docx`, "-WindowStyle", "Hidden")
if err := cmd_instance.Start(); err != nil {
log.Println(err)
}
By using this, I can call a Word process without invoking a PowerShell terminal.
I don't know "Go" language, but, if you can call the MS Word absolute path, could you try this:
"C:\Program Files (x86)\Microsoft Office\root\Office16\WINWORD.EXE" 'C:\Support\File.docx'
In PowerShell, i call like that:
& "C:\Program Files (x86)\Microsoft Office\root\Office16\WINWORD.EXE" 'C:\Support\File.docx'

Find location of Golang application

I have a Golang application which is being deployed into a container via Kubernetes. Within the service I would like to read a file which is nested within the application.
I'm struggling to find out how to set the current working directory to the location of the application.
Currently the application panics with an error due to the relative paths not being aligned:
open /workspace/source/package/file.csv: no such file or directory
I've tried using the following code and appending the file name:
var (
_, b, _, _ = runtime.Caller(0)
basepath = filepath.Dir(b)
)
However this still doesn't work. Is there a way to find the applications current location and then append the filename?
Thanks for help!
Use os.Executable to find the path to the executable.
b, err := os.Executable()
if err != nil {
log.Fatal(err)
}
basepath := filepath.Dir(b)
Can't you just cd before executing the application? Then you can use relative paths.

Golang os.Rename(<fromDir>,<toDir>) not working in Windows

Using Go - lang, according to the documentation, the os.Rename should be able to rename either a file or directory on any operating system.
On Linux it works as it should, pass either a file or directory into it and the file or directory are moved.
On windows i recieve an 'Access is denied' Error when trying to pass a folder.
It works 100% for files.
example:
source = c:\sourcefolder
destination = c:\destinationfolder
source contains:
C:\sourcefolder\file1.xml
C:\sourcefolder\file2.xml
C:\sourcefolder\foldername1
C:\sourcefolder\foldername1\file3.xml
C:\sourcefolder\foldername2
C:\sourcefolder\foldername2\file4.xml
both file1.xml and file2.xml will successfully copy to c:\destination.
But the folders and files within the folders crash out with access denied
The script is pretty simple:
source := "C:\\sourcefolder"
destination := "C:\\destinationfolder"
pathSeperator := "\\"
files, err := ioutil.ReadDir(source)
if err != nil {
fmt.Println("Move command execution error: ", err)
}
for _, f := range files {
fmt.Println(f.Name())
fmt.Println(f.Mode())
err := os.Rename(source+pathSeperator+f.Name(), destination+pathSeperator+f.Name())
if err != nil {
fmt.Println("Move command execution error: ", err)
panic(err)
}
}
Having searched stackoverflow and golang's resources, i found the issue listed in 2016 that reported this fault and according to the issue it was fixed, but i am unable to get this to work. Nowhere else that i can find lists this issue go golang.
checking the f.Mode for access, i get drwxrwxrwx and have complete access to all the files and directories.
Any help with this would be great, racking my mind. Thank you.
Quoted from comment. solved my issue.
Found the cause of the fault to be, if a windows explorer window is
open and has ANY visibility of the folders being moved (i.e. in the
tree on the left or right-pane) then access is denied as it can not
move the folders. If i minimize all the tree's so that the
source\destination folders are not visible and select a different sub
folder in windows explorer then the os.Rename works as it should,
moving all content from A to B really quick (as per linux)
I had the same issue with copying files within the same folder. The following solution works just fine (without closing or minimizing windows):
// read original file
origFile, _:= os.ReadFile(filePath)
// create new file with a different name
newFile, _ := os.Create(filePath + ".new")
// print data from original file to new file.
fmt.Fprintf(newFile, "%s", string(origFile))

File path in golang

I have a project with next structure:
|_main.go
|_config
|_config.go
|_config_test.go
|_config.json
I'm having next code line in config.go:
file, _ := os.Open("config/config.json")
When I'm executing method contained this code line from main.go all is working. But when I'm trying to execute this method from config_test.go it produces error:
open config/config.json: no such file or directory
As I understood it is a working directory issue because I'm launching same code with relative path from different directories. How can I fix this problem without using full path in config.go?
Relative paths are always resolved basis your current directory. Hence it's better to avoid relative paths.
Use command line flags or a configuration management tool (better approach) like Viper
Also according to The Twelve-Factor App your config files should be outside your project.
Eg usage with Viper:
import "github.com/spf13/viper"
func init() {
viper.SetConfigName("config")
// Config files are stored here; multiple locations can be added
viper.AddConfigPath("$HOME/configs")
errViper := viper.ReadInConfig()
if errViper != nil {
panic(errViper)
}
// Get values from config.json
val := viper.GetString("some_key")
// Use the value
}

Checking with os.Stat vs just os.MkdirAll

I need to write to a file in a nested directory that may or may not exist.
At first, I checked if the folder existed via os.Stat, doing os.MkdirAll if it doesn't exist, and then opening and writing to a file.
I tried removing the os.Stat and just doing os.MkdirAll, and it appears to work - meaning os.MkdirAll is idempotent.
My question is, is there a benefit of doing the os.Stat check? Is it a much lighter operation than os.MkdirAll?
The first thing MkdirAll does is call os.Stat to check if the path exists and is a directory.
func MkdirAll(path string, perm FileMode) error {
// Fast path: if we can tell whether path is a directory or file, stop with success or error.
dir, err := Stat(path)
if err == nil {
if dir.IsDir() {
return nil
}
return &PathError{"mkdir", path, syscall.ENOTDIR}
}
...
From the docs:
If path is already a directory, MkdirAll does nothing and returns nil.
So no, you don't need to call os.Stat.

Resources