Web app and cli tutorial
parent
bc1b19c975
commit
55378404b3
@ -0,0 +1,5 @@
|
||||
# Go Gopher CLI Tutorial
|
||||
|
||||
https://dev.to/aurelievache/learning-go-by-examples-part-3-create-a-cli-app-in-go-1h43
|
||||
|
||||
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright © 2024 NAME HERE <EMAIL ADDRESS>
|
||||
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "go-gopher-cli",
|
||||
Short: "Retrieve your favorite gopher",
|
||||
Long: `Retrieve your favorite gopher:
|
||||
|
||||
That's right, you get your gopher and can eat it too...not really
|
||||
of course.`,
|
||||
// Uncomment the following line if your bare application
|
||||
// has an action associated with it:
|
||||
// Run: func(cmd *cobra.Command, args []string) { },
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Here you will define your flags and configuration settings.
|
||||
// Cobra supports persistent flags, which, if defined here,
|
||||
// will be global for your application.
|
||||
|
||||
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.go-gopher-cli.yaml)")
|
||||
|
||||
// Cobra also supports local flags, which will only run
|
||||
// when this action is called directly.
|
||||
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
module go-gopher-cli
|
||||
|
||||
go 1.21.0
|
||||
|
||||
require (
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/spf13/cobra v1.8.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
)
|
@ -0,0 +1,10 @@
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
@ -0,0 +1,11 @@
|
||||
/*
|
||||
Copyright © 2024 NAME HERE <EMAIL ADDRESS>
|
||||
|
||||
*/
|
||||
package main
|
||||
|
||||
import "go-gopher-cli/cmd"
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
}
|
@ -0,0 +1 @@
|
||||
gowiki/wiki
|
@ -0,0 +1,4 @@
|
||||
# Go Web App
|
||||
|
||||
https://go.dev/doc/articles/wiki/
|
||||
|
@ -0,0 +1 @@
|
||||
This is a test page.
|
@ -0,0 +1 @@
|
||||
This is a page
|
@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
// A wiki consists of a series of interconnected pages, each of which has a title and a body
|
||||
type Page struct {
|
||||
Title string
|
||||
//The Body element is a []byte rather than string because that is the type expected by the io libraries we will use
|
||||
Body []byte
|
||||
}
|
||||
|
||||
// save Saves a page to disk.
|
||||
func (p *Page) save() error {
|
||||
filename := p.Title + ".txt"
|
||||
return os.WriteFile(filename, p.Body, 0600)
|
||||
}
|
||||
|
||||
// loadPage loads a Page from disk.
|
||||
// It takes the title of the page as an argument, reads the corresponding
|
||||
// file, and returns a pointer to a Page struct containing the title and body.
|
||||
// If an error occurs during reading, it returns the error.
|
||||
func loadPage(title string) (*Page, error) {
|
||||
filename := title + ".txt"
|
||||
body, err := os.ReadFile(filename)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{Title: title, Body: body}, nil
|
||||
}
|
||||
|
||||
func viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
html := "<h1>%s</h1><div>%s</div>"
|
||||
filename := r.URL.Path[len("/view/"):]
|
||||
page, _ := loadPage(filename)
|
||||
fmt.Fprintf(w, html, page.Title, page.Body)
|
||||
}
|
||||
|
||||
func editHandler(w http.ResponseWriter, r *http.Request) {
|
||||
title := r.URL.Path[len("/edit/"):]
|
||||
page, err := loadPage(title)
|
||||
if err != nil {
|
||||
page = &Page{Title: title}
|
||||
}
|
||||
fmt.Fprintf(w, "<h1>Editing %s</h1>"+
|
||||
"<form action=\"/save/%s\" method=\"POST\">"+
|
||||
"<textarea name=\"body\">%s</textarea><br>"+
|
||||
"<input type=\"submit\" value=\"Save\">"+
|
||||
"</form>",
|
||||
page.Title, page.Title, page.Body)
|
||||
|
||||
}
|
||||
|
||||
func saveHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/view/", viewHandler)
|
||||
http.HandleFunc("/edit/", editHandler)
|
||||
http.HandleFunc("/save/", saveHandler)
|
||||
|
||||
log.Println("Serving on: http://0.0.0.0:5001")
|
||||
log.Fatal(http.ListenAndServe(":5001", nil))
|
||||
}
|
||||
|
||||
// func main() {
|
||||
// p1 := &Page{Title: "TestPage", Body: []byte("This is a test page.")}
|
||||
// p1.save()
|
||||
// p2, _ := loadPage("TestPage")
|
||||
// fmt.Println(string(p2.Body))
|
||||
// }
|
Loading…
Reference in New Issue