I need to get the currently logged in user(s) on the local Windows machine, using Golang. I'm not looking for the user currently running the application, which can be got from the built-in function user.Current().
I can call query user from cmd and this gives me the list (string manipulation required, but that is not a problem) of users I need.
The code I have tried is:
out, err := exec.Command("query", "user")
if err != nil {
panic(err)
}
// ...do something with 'out'
This produces the error panic: exit status 1. The same occurs if I do:
out, err := exec.Command("cmd", "/C", "query", "user")
...
As usually with such kind of questions,
the solution is to proceed like this:
Research (using MSDN and other sources) on how to achieve the
stated goal using Win32 API.
Use the built-in syscall package (or, if available/desirable,
helper 3rd-party packages) to make those calls from Go.
The first step can be this
which yields the solution
which basically is "use WTS".
The way to go is to
Connect to the WTS subsystem¹.
Enumerate the currently active sessions.
Query each one for the information about the
identity of the user associated with it.
The second step is trickier but basically you'd need to research
how others do that.
See this
and this
and this for a few examples.
You might also look at files named _windows*.go in
the Go source of the syscall package.
¹ Note that even on a single-user machine, everything
related to seat/session management comes through WTS
(however castrated it is depending on a particular flavor of Windows). This is true since at least XP/W2k3.
package main
import (
"fmt"
"os/exec"
)
func main() {
out, err := exec.Command("cmd", "/C", "query user").Output()
if err != nil {
fmt.Println("Error: ", err)
}
fmt.Println(string(out))
}
Related
If I use GORM, there is no migration file?? So far, I googled and searched for this information, there is no migration file in GORM based on my understanding, and If I want to generate a migration file I have to use CLI. The reason why the GORM didn't generate a migration file is that " It WON’T delete unused columns to protect your data." (https://gorm.io/docs/migration.html#Auto-Migration)
How do we keep track of the changes? In Django, it generates a migration file, and we can keep track of the changes whenever we migrate.
In advance, I am sorry if I understand something wrong... I am just getting started learning golang and database a few days ago.
I believe GORM doesn't have the solution you want. There are some CLIs from the GORM team and from other enthusiasts but they really don't do what we actually want (Yep, I needed the same tool as well). At the end of the day, only GIT is the friend in the case of using GORM.
P.S. I found a good solution in Facebook's Ent(The entity framework for Go) which is a significantly better option for interacting with DBs in Go. They have a built-in solution for your needs - the WriteTo function which writes the schema changes to f instead of running them against the database.
func main() {
client, err := ent.Open("mysql", "root:pass#tcp(localhost:3306)/test")
if err != nil {
log.Fatalf("failed connecting to mysql: %v", err)
}
defer client.Close()
ctx := context.Background()
// Dump migration changes to an SQL script.
f, err := os.Create("migrate.sql")
if err != nil {
log.Fatalf("create migrate file: %v", err)
}
defer f.Close()
if err := client.Schema.WriteTo(ctx, f); err != nil {
log.Fatalf("failed printing schema changes: %v", err)
}
}
Or you can simply print the changes to the terminal by setting os.Stdout as a target output location for WriteTo.
client.Schema.WriteTo(ctx, os.Stdout)
The reference | Database Migration - Offline Mode
I hope, this will help you to have a better option next time by using Ent which is created, open-sourced, and maintained by Facebook for its needs and scale. Also, you might be interested in the post from Ariel Mashraki - Introducing ent.
Objective
Add a command to dropbox's CLI tool to get the shared link for the given path (file or folder).
The changes are here: github fork.
Background
The dropbox-go-sdk has a function that takes a path, and returns a new shared link, or returns an error containing the existing shared link.
I don't know how to use the error to extract the existing shared link.
Code
on github, and snippet here:
dbx := sharing.New(config)
res, err := dbx.CreateSharedLinkWithSettings(arg)
if err != nil {
switch e := err.(type) {
case sharing.CreateSharedLinkWithSettingsAPIError:
fmt.Printf("%v", e.EndpointError)
default:
return err
}
}
This prints the following:
&{{shared_link_already_exists} <nil> <nil>}found unknown shared link typeError: shared_link_already_exists/...
tracing:
CreateSharedLinkWithSettings --> CreateSharedLinkWithSettingsAPIError --> CreateSharedLinkWithSettingsError --> SharedLinkAlreadyExistsMetadata --> IsSharedLinkMetadata
IsSharedLinkMetadata contains the Url that I'm looking for.
More Info
The API docs point to CreateSharedLinkWithSettings, which should pass back the information in the error including the existing Url.
I struggle to understand how to deal with the error and extract the url from it.
The dbxcli has some code doing a similar operation, but again, not sure how it's working enough to apply it to the code I'm working on. Is it a Struct? Map? I don't know what this thing is called. There's some weird magic err.(type) stuff happening in the code. How do I access the data?
dbx := sharing.New(config)
res, err := dbx.CreateSharedLinkWithSettings(arg)
if err != nil {
switch e := err.(type) {
case sharing.CreateSharedLinkWithSettingsAPIError:
fmt.Printf("%v", e.EndpointError)
// type cast to the specific error and access the field you want.
settingsError := err.(sharing.CreateSharedLinkWithSettingsAPIError)
fmt.Println(settingsError.EndpointError.SharedLinkAlreadyExists.Metadata.Url)
default:
return err
}
}
The question was answered in the comments by #jimb. The answer is you access the fields like any other golang data structure - nothing special.
The errors I got when trying to access the fields were because the fields were not there.
The problem with the code was dependency issues. The code depends on an older version of the go-sdk and I referenced the latest version.
This question serves as a good explanation for how real golang programmers handle errors in their code with examples. I wasn't able to find this online, so I won't close the question.
I am developing a CLI tool and in cases where the things go wrong, I want to log the custom error and exit with panic. The issue with panic is that an exit by panic is followed by the stack trace which I don't want to show to the user. Is there a way to panic and have a ninja-like stealthy/quiet exit?
(Choosing panic over os.Exit() since that would handle any defer and also seems a lot cleaner.)
Well, a direct answer is yes, there is a way:
panic with an error of a custom, "sentinel", type, or with a custom, "sentinel", value, then
Have a defer-red call in main which recover()-s the panic and checks whether the returned value is of a sentinel type (or equals to a sentinel value—the exact approach is up to you).
If it detects a "known" error, it silently exits with a non-zero exit code;
otherwise it panics again.
But honestly I think your mindset is too affected by programming languages with exceptions: I have yet to see a CLI app which would have any difficulty in handling errors "the usual way" or would actually benefit from bailing out using panic.
A counter-argument to the approach you're craving for is this: bubbling up an error allows adding more context to it on each level of the call stack being unwound, where it makes sense,—producing as useful as possible error to display.
Basically, it works like this:
func main() {
...
err := DoStuff()
if err != nil {
log.Fatal("failed to do stuff: ", err)
}
...
}
func DoStuff() error {
foo, err := InitializeWhatever()
if err != nil {
return fmt.Errorf("failed to inialize whatever: %w", err)
}
...
return nil
}
func InitializeWhatever() (*Whatever, error) {
handle, err := OpenWhateverElse()
if err != nil {
return nil, fmt.Errorf("failed to open whatever else: %w", err)
}
...
return whatever, nil
}
…which would produce something like
failed to do stuff: failed to inialize whatever: failed to open whatever else: task failed successfully
…which makes it crystal clear which sequence of events led to the undesired outcome.
Sure, as usually, YMMV and no one except you knows your situation best, but still it's something to ponder.
And here's an assorted list of thoughts on what I've written above.
The approach with panicking with a known value / error of a known type is actually nothing new—for instance, see net/http.ErrAbortHandler.
The encoding/json package used to employ this approach for breaking out of multiple nested loops (has been reworked since then, though).
Still, some experts consider sentinel errors to be bad design and recommend instead asserting (using Go's type assertions) behaviour of the errors—for instance, you can look at how net.Error has Timeout and Temporary methods which allows to not have concrete exported types for temporary errors, and errors due to timeouts, and their combinations,—but instead have them all support a common set of methods which allow the callers to make sense of the error's nature.
Since 1.13, Go gained advanced support for "wrapping" errors—producing matryoshka-style error chains, and this allows an approach to error handling which sits somewhere between the two extremes above: one can create an error of a particular type at the place an error was first found, then wrap it in contexts as they bubble up the call stack, and then assert the type of the innermost error at the place which handles the error. A friendly explanation on how it works.
Well, and I'd recommend reading this for, I must admit, had you already done this, you'd probably not ask your question in the first place ;-)
How can I track down a function return mismatch in Golang? In two different build environments I am seeing a difference. Both cases should be Visual Studio Code remote to a Linux box, using Go 1.12 in module mode. The broken case is where I am driving the build using the Golang:1.12 Docker image. Below is simplified from where I'm seeing the problem.
So for this sample, derived from https://github.com/satori/go.uuid:
package main
import (
"fmt"
uuid "github.com/satori/go.uuid"
)
func main() {
// or error handling
u2, err := uuid.NewV4()
if err != nil {
fmt.Printf("Something went wrong: %s", err)
return
}
fmt.Printf("UUIDv4: %s\n", u2)
}
The unexpected build error is:
./main.go:11:5 assignment mismatch: 2 variables but uuid.NewV4() returns 1 values
In the environment where I encounter this problem, in Visual Studio Code when I hover with mouse over the call to uuid.NewV4() I see:
func uuid.NewV4() (uuid.UUID, error)
uuid.NewV4 on pkg.go.dev
NewV4 returns random generated UUID.
and hover over uuid shows:
package uuid ("github.com/satori/go.uuid")
uuid on pkg.go.dev
I may switch to a different uuid package to work around this -- but I want to understand better how to figure this out.
I guess problem is in different github.com/satori/go.uuid module versions. You can see, that NewV4 function signature was updated to NewV4() (uuid.UUID, error) in latest version v1.2.0. Before that it was func NewV4() UUID
Then resolve to a specific version as in this question:
How to point Go module dependency in go.mod to a latest commit in a repo?
Golang provides the file package to access Cloud Storage.
The package's Create function requires the io.WriteCloser interface. However, I have not found a single sample or documentation showing how to actually save a file to Cloud Storage.
Can anybody help? Is there a higher level implementation of io.WriteCloser that would allow us to store files in Cloud Storage? Any sample code?
We've obviously tried to Google it ourselves but found nothing and now hope for the community to help.
It's perhaps true than the behavior is not well defined in the documentation.
If you check the code: https://code.google.com/p/appengine-go/source/browse/appengine/file/write.go#133
In each call to Write the data is sent to the cloud (line 139). So you don't need to save. (You should close the file when you're done, through.)
Anyway, I'm confused with your wording: "The package's Create function requires the io.WriteCloser interface." That's not true. The package's Create functions returns a io.WriteCloser, that is, a thingy you can write to and close.
yourFile, _, err := Create(ctx, "filename", nil)
// Check err != nil here.
defer func() {
err := yourFile.Close()
// Check err != nil here.
}()
yourFile.Write([]byte("This will be sent to the file immediately."))
fmt.Fprintln(yourFile, "This too.")
io.Copy(yourFile, someReader)
This is how interfaces work in Go. They just provide you with a set of methods you can call, hiding the actual implementation from you; and, when you just depend on a particular interface instead of a particular implementation, you can combine in multiple ways, as fmt.Fprintln and io.Copy do.