I am new to golang and trying to explore the lang with sample hobby
project for that I need to write the below tree like structure.
Its like File system, one Folder will have many Folder and files.
And tree structure goes on until it has no further branch.
[Fol]
[Fol,Fol,Fol] [Fil,Fil,Fil]
My solution to have:
type Fol struct{
slice of Fol
slice of Fil
}
Its taking time for me to design, So any once help is very much appreciated.
Regards,
Vineeth
Finally I used solution provided in below link:
https://stackoverflow.com/a/12659537/430294
Something like this?
Playground link
package main
import "fmt"
type File struct {
Name string
}
type Folder struct {
Name string
Files []File
Folders []Folder
}
func main() {
root := Folder{
Name: "Root",
Files: []File{
{"One"},
{"Two"},
},
Folders: []Folder{
{
Name: "Empty",
},
},
}
fmt.Printf("Root %#v\n", root)
}
Prints
Root main.Folder{Name:"Root", Files:[]main.File{main.File{Name:"One"}, main.File{Name:"Two"}}, Folders:[]main.Folder{main.Folder{Name:"Empty", Files:[]main.File(nil), Folders:[]main.Folder(nil)}}}
Related
Using this guide https://the-guild.dev/graphql/codegen/docs/advanced/generated-files-colocation
It works as intended for "operation-types" file, but how about the "types.ts" file itself, is it possible to generate separate type file depending for each operation needs, or just create the object types inside the ".generated.tsx" file?
my config is as follow, similar to the docs, its just putting into a folder called __generated__. Thank you.
const config: CodegenConfig = {
schema: 'http://localhost:4000/graphql',
documents: ['src/**/*.{gql,graphql}'],
generates: {
'src/codegen/types.ts': {
plugins: ['typescript'],
},
'src/': {
preset: 'near-operation-file',
presetConfig: { extension: '.generated.tsx', baseTypesPath: 'codegen/types.ts', folder: '__generated__' },
plugins: ['typescript-operations'],
}
}
}
Is is possible, and if so how, to let a Command initialize a resource and pass it down to its Subcommands. Image an application that takes its arguments like
$ mycmd db --connect <...> create <...>
$ mycmd db --connect <...> update <...>
This may not be a great example but it illustrates the concept. Here db is some resource that all the subcommands depend on. I would like a single function to be responsible for the initialization of the db resource and then pass the initialized resource down to the subcommands. I can't figure out how to do this with urfave/cli/v2 .
You could do it by creating two separate cli.Apps, one that parses the db part of the arguments just to create a context.Context with context.WithValue and then use that context to create the second cli.App which would parse the remainder of the arguments. I'm sure there's a better way to do it.
I'm grateful for any help!
You can achieve this with context values. You set the value in the Before callback of the parent Command. Below code is copied and modified from the subcommands example:
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/urfave/cli/v2"
)
func main() {
app := &cli.App{
Commands: []*cli.Command{
{
Name: "db",
Before: func(c *cli.Context) error {
db := "example"
c.Context = context.WithValue(c.Context, "db", db)
return nil
},
Subcommands: []*cli.Command{
{
Name: "connect",
Action: func(c *cli.Context) error {
db := c.Context.Value("db").(string) // remember to assert to original type
fmt.Println("sub command:", db)
return nil
},
},
},
},
},
}
err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}
This main uses a string so that you can copy paste and run it. You can replace string with your DB object.
How to test:
$ go build -o example
$ ./example db connect
sub command: example
This is newbie question. The dependencies seems to be on github, and it's pretty obvious from the import, so why run doesn't work?
Error is: no required module provides package github.com/hashicorp/go-getter
package main
import (
"context"
"fmt"
"os"
// Problem with line below, getting error: no required module provides package
getter "github.com/hashicorp/go-getter"
)
func main() {
client := &getter.Client{
Ctx: context.Background(),
//define the destination to where the directory will be stored. This will create the directory if it doesnt exist
Dst: "/tmp/gogetter",
Dir: true,
//the repository with a subdirectory I would like to clone only
Src: "github.com/hashicorp/terraform/examples/cross-provider",
Mode: getter.ClientModeDir,
//define the type of detectors go getter should use, in this case only github is needed
Detectors: []getter.Detector{
&getter.GitHubDetector{},
},
//provide the getter needed to download the files
Getters: map[string]getter.Getter{
"git": &getter.GitGetter{},
},
}
//download the files
if err := client.Get(); err != nil {
fmt.Fprintf(os.Stderr, "Error getting path %s: %v", client.Src, err)
os.Exit(1)
}
//now you should check your temp directory for the files to see if they exist
}
Create a folder somewhere called getter, then create a file
getter/getter.go:
package main
import (
"fmt"
"github.com/hashicorp/go-getter/v2"
)
func main() {
fmt.Println(getter.ErrUnauthorized)
}
Notice I didn't use a name like you specified, as it's redundant in this case. The package is already called getter [1], so you don't need to specify the same name. Then, run:
go mod init getter
go mod tidy
go build
https://pkg.go.dev/github.com/hashicorp/go-getter/v2
In a golang CLI I'm programming I collect information on how to configure the tool and I marhsal that as a YAML file. However, I'm not sure how I would add line breaks to make the file more readable?
type Config struct {
Author string `yaml:"author"`
License string `yaml:"license"`
// Marhsal a line break here
Workspace string `yaml:"workspace"`
Description string `yaml:"description"`
// Marhsal a line break here
Target string `yaml:"target"`
}
One way to implement this that allows format (and comments) is to use a template engine.
Here is a running example that generates a string with the formatted yaml, that can be then saved to a .yml file.
No additional libraries are needed and the template is included inside the go file.
package main
import (
"bytes"
"fmt"
"text/template"
)
type Config struct {
Author string
License string
Workspace string
Description string
Target string
}
const cfg_template = `
conf:
author: {{ .Author }}
licence: {{ .License }}
workspace: {{ .Workspace }}
description: {{ .Description }}
# you can even add comments to the template
target: {{ .Target }}
# other hardcoded config
foo: bar
`
func generate(config *Config) string {
t, err := template.New("my yaml generator").Parse(cfg_template)
if err != nil {
panic(err)
}
buf := &bytes.Buffer{}
err = t.Execute(buf, config)
if err != nil {
panic(err)
}
return buf.String()
}
func main() {
c := Config{
Author: "Germanio",
License: "MIT",
Workspace: "/home/germanio/workspace",
Description: "a cool description",
Target: "/home/germanio/target",
}
yaml := generate(&c)
fmt.Printf("yaml:\n%s", yaml)
}
The result looks like this:
$ go run yaml_generator.go
yaml:
conf:
author: Germanio
licence: MIT
workspace: /home/germanio/workspace
description: a cool description
# you can even add comments to the template
target: /home/germanio/target
# other hardcoded config
foo: bar
I'm sure there are better ways to implement it, just want to show a quick working example.
As empty line don't have a meaning in yaml, the default library does not create them, and does not expose an option to do so in the struct field tag.
However, if you want fine grained control of how a type is marshalled in yaml, you can always make it implements yaml.Marshaller by defining a method MarshalYAML() (interface{}, error)
I have a Go struct for which I want to generate an OpenAPI schema automatically. Once I have an OpenAPI definition of that struct I wanna generate JSONSchema of it, so that I can validate the input data that comes and is gonna be parsed into those structs.
The struct looks like the following:
// mySpec: io.myapp.MinimalPod
type MinimalPod struct {
Name string `json:"name"`
// k8s: io.k8s.kubernetes.pkg.api.v1.PodSpec
v1.PodSpec
}
Above struct is clearly an augmentation of what Kubernetes PodSpec is.
Now the approach that I have used is to generate definition part for my struct MinimalPod, the definition for PodSpec will come from upstream OpenAPI spec of Kubernetes. PodSpec has a key io.k8s.kubernetes.pkg.api.v1.PodSpec in the upstream OpenAPI spec, this definition is injected from there in my Properties. Now in my code that parses above struct I have templates of what to do if struct field is string.
If the field has a comment that starts with k8s: ... the next part is Kubernetes object's OpenAPI definition key. In our case the OpenAPI definition key is io.k8s.kubernetes.pkg.api.v1.PodSpec. So I retrieve that field's definition from the upstream OpenAPI definition and embed it into the definition of my struct.
Once I have generated an OpenAPI definition for this struct which is injected in Kubernetes OpenAPI schema's definition with key being io.myapp.MinimalPod. Now I can use the tool openapi2jsonschema to generate JSONSchema out of this one. Which generates a JSONSchema file named MinimalPod.json.
Now jsonschema tool and the file MinimalPod.json can be used for validating input given to my tool parser to see if all fields were given right.
Is this the right approach of doing things, or is there a tool/library and if I feed Go structs to it, it gives me OpenAPI schema? It would be fine if it does not identify where to inject Kubernetes OpenAPI schema from even automatic parsing of Go structs and giving OpenAPI definition would be much appreciated.
Update 1
After following #mehdy 's instructions, this is what I have tried:
I have used this import path github.com/kedgeproject/kedge/vendor/k8s.io/client-go/pkg/api/v1 to import the PodSpec definition instead of k8s.io/api/core/v1 and code looks like this:
package foomodel
import "github.com/kedgeproject/kedge/vendor/k8s.io/client-go/pkg/api/v1"
// MinimalPod is a minimal pod.
// +k8s:openapi-gen=true
type MinimalPod struct {
Name string `json:"name"`
v1.PodSpec
}
Now when I generate the same with flag -i changed from k8s.io/api/core/v1 to github.com/kedgeproject/kedge/vendor/k8s.io/client-go/pkg/api/v1
$ go run example/openapi-gen/main.go -i k8s.io/kube-openapi/example/model,github.com/kedgeproject/kedge/vendor/k8s.io/client-go/pkg/api/v1 -h example/foomodel/header.txt -p k8s.io/kube-openapi/example/foomodel
This is what is generated:
$ cat openapi_generated.go
// +build !ignore_autogenerated
/*
======
Some random text
======
*/
// This file was autogenerated by openapi-gen. Do not edit it manually!
package foomodel
import (
spec "github.com/go-openapi/spec"
common "k8s.io/kube-openapi/pkg/common"
)
func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
return map[string]common.OpenAPIDefinition{
"k8s.io/kube-openapi/example/model.Container": {
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "Container defines a single application container that you want to run within a pod.",
Properties: map[string]spec.Schema{
"health": {
SchemaProps: spec.SchemaProps{
Description: "One common definitions for 'livenessProbe' and 'readinessProbe' this allows to have only one place to define both probes (if they are the same) Periodic probe of container liveness and readiness. Container will be restarted if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes",
Ref: ref("k8s.io/client-go/pkg/api/v1.Probe"),
},
},
"Container": {
SchemaProps: spec.SchemaProps{
Ref: ref("k8s.io/client-go/pkg/api/v1.Container"),
},
},
},
Required: []string{"Container"},
},
},
Dependencies: []string{
"k8s.io/client-go/pkg/api/v1.Container", "k8s.io/client-go/pkg/api/v1.Probe"},
},
}
}
I get only this much of the configuration generated. While when I switch back to "k8s.io/api/core/v1" I get config code auto generated which is more than 8k lines. What am I missing here?
Here definition of k8s.io/client-go/pkg/api/v1.Container and k8s.io/client-go/pkg/api/v1.Probe is missing while when I use k8s.io/api/core/v1 as import everything is generated.
Note: To generate above steps, please git clone https://github.com/kedgeproject/kedge in GOPATH.
You can use kube-openapi package for this. I am going to add a sample to the repo but I've tested this simple model:
// Car is a simple car model.
// +k8s:openapi-gen=true
type Car struct {
Color string
Capacity int
// +k8s:openapi-gen=false
HiddenFeature string
}
If you assume you created this file in
go run example/openapi-gen/main.go -h example/model/header.txt -i k8s.io/kube-openapi/example/model -p k8s.io/kube-openapi/example/model
(you also need to add a header.txt file). You should see a new file created in example/model folder called openapi_generated.go. This is an intermediate generated file that has your OpenAPI model in it:
func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
return map[string]common.OpenAPIDefinition{
"k8s.io/kube-openapi/example/model.Car": {
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "Car is a simple car model.",
Properties: map[string]spec.Schema{
"Color": {
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
Format: "",
},
},
"Capacity": {
SchemaProps: spec.SchemaProps{
Type: []string{"integer"},
Format: "int32",
},
},
},
Required: []string{"Color", "Capacity"},
},
},
Dependencies: []string{},
},
}
}
From there you should be able to call the generated method, get the model for your Type and get its Schema.
With some go get magic and changing the command line a little, I was able to generate the model for your model. Here is what you should change in your code:
package model
import "k8s.io/api/core/v1"
// MinimalPod is a minimal pod.
// +k8s:openapi-gen=true
type MinimalPod struct {
Name string `json:"name"`
v1.PodSpec
}
and then change the run command a little to include PodSpec in the generation:
go run example/openapi-gen/main.go -h example/model/header.txt -i k8s.io/kube-openapi/example/model,k8s.io/api/core/v1 -p k8s.io/kube-openapi/example/model
Here is what I got: https://gist.github.com/mbohlool/e399ac2458d12e48cc13081289efc55a