Skip to content

Commit a9b33ae

Browse files
committed
first pass at til, with barebones new and compile cmds
1 parent a4e6695 commit a9b33ae

File tree

9 files changed

+309
-0
lines changed

9 files changed

+309
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
posts/

cmd/compile.go

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package cmd
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
)
6+
7+
var compileCmd = &cobra.Command{
8+
Use: "compile",
9+
// Aliases: []string{"c"},
10+
Short: "compile markdown files into rss feed",
11+
Run: func(cmd *cobra.Command, args []string) {
12+
Compile()
13+
},
14+
}
15+
16+
func init() {
17+
rootCmd.AddCommand(compileCmd)
18+
}

cmd/new.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package cmd
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
)
6+
7+
var newCmd = &cobra.Command{
8+
Use: "new",
9+
// Aliases: []string{"n"},
10+
Short: "new markdown file",
11+
Long: "create a new markdown file for a blog post",
12+
Args: cobra.ExactArgs(1),
13+
Run: func(cmd *cobra.Command, args []string) {
14+
New(args[0])
15+
},
16+
}
17+
18+
func init() {
19+
rootCmd.AddCommand(newCmd)
20+
}

cmd/root.go

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"github.com/spf13/cobra"
6+
"os"
7+
)
8+
9+
var rootCmd = &cobra.Command{
10+
Use: "til",
11+
Short: "til is a cli tool for generating rss posts from markdown files",
12+
Long: "til is a cli tool for generating rss posts from markdown files",
13+
Run: func(cmd *cobra.Command, args []string) {
14+
15+
},
16+
}
17+
18+
func Execute() {
19+
if err := rootCmd.Execute(); err != nil {
20+
fmt.Fprintf(os.Stderr, "oh no! something went wrong while executing til '%s'\n", err)
21+
os.Exit(1)
22+
}
23+
}

cmd/til.go

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package cmd
2+
3+
import (
4+
"encoding/xml"
5+
// "errors"
6+
"fmt"
7+
"os"
8+
"path/filepath"
9+
"time"
10+
11+
"github.com/russross/blackfriday/v2"
12+
// "github.com/charmbracelet/bubbletea" // TODO make bubbletea editing ui
13+
)
14+
15+
// RSS-related structs
16+
type RSS struct {
17+
XMLName xml.Name `xml:"rss"`
18+
Version string `xml:"version,attr"`
19+
Channel Channel `xml:"channel"`
20+
}
21+
22+
type Channel struct {
23+
Title string `xml:"title"`
24+
Link string `xml:"link"`
25+
Description string `xml:"description"`
26+
LastBuildDate string `xml:"lastBuildDate"`
27+
Items []Item `xml:"item"`
28+
}
29+
30+
type Item struct {
31+
Title string `xml:"title"`
32+
Link string `xml:"link"`
33+
Description string `xml:"description"`
34+
PubDate string `xml:"pubDate"`
35+
}
36+
37+
func New(filename string) {
38+
// TODO add flag to use or not use the template...
39+
templateFile := "posts/template.md" // TODO make this a configurable thing
40+
postsDir := "./posts" // TODO make this a configurable thing
41+
42+
err := os.MkdirAll(postsDir, os.ModePerm)
43+
if err != nil {
44+
fmt.Printf("error creating directory: %v\n", err)
45+
return
46+
}
47+
48+
mdFile := filepath.Join(postsDir, filename+".md")
49+
50+
if _, err := os.Stat(templateFile); os.IsNotExist(err) {
51+
fmt.Printf("template file does not exist: %s\n", templateFile)
52+
return
53+
}
54+
55+
templateContent, err := os.ReadFile(templateFile)
56+
if err != nil {
57+
fmt.Printf("error reading template file: %v\n", err)
58+
return
59+
}
60+
61+
err = os.WriteFile(mdFile, templateContent, os.ModePerm)
62+
if err != nil {
63+
fmt.Printf("error writing to new file: %v\n", err)
64+
return
65+
}
66+
}
67+
68+
func Compile() {
69+
fmt.Printf("compiling...")
70+
71+
postsDir := "./posts" // TODO make this configurable
72+
siteURL := "http://localhost:8000" // TODO change to my site URL
73+
74+
// initialize rss feed
75+
rss := RSS{
76+
Version: "2.0",
77+
Channel: Channel{
78+
Title: "lili til", // TODO configure
79+
Link: siteURL,
80+
Description: "my posts",
81+
LastBuildDate: time.Now().Format(time.RFC1123),
82+
},
83+
}
84+
85+
// read all markdown files
86+
err := filepath.Walk(postsDir, func(path string, info os.FileInfo, err error) error {
87+
if err != nil {
88+
return err
89+
}
90+
91+
if !info.IsDir() && filepath.Ext(path) == ".md" {
92+
content, err := os.ReadFile(path)
93+
if err != nil {
94+
return err
95+
}
96+
97+
// convert markdown content to HTML using black friday
98+
htmlContent := blackfriday.Run(content)
99+
100+
// create an RSS item for this post
101+
item := Item{
102+
Title: info.Name(),
103+
Link: fmt.Sprintf("%s/%s", siteURL, info.Name()),
104+
Description: string(htmlContent),
105+
PubDate: info.ModTime().Format(time.RFC1123),
106+
}
107+
108+
// Add the item to the RSS feed
109+
rss.Channel.Items = append(rss.Channel.Items, item)
110+
}
111+
112+
return nil
113+
})
114+
115+
if err != nil {
116+
fmt.Println("error reading folder:", err)
117+
return
118+
}
119+
120+
// make xml file
121+
output, err := xml.MarshalIndent(rss, "", " ")
122+
if err != nil {
123+
fmt.Println("error marshalling XML:", err)
124+
return
125+
}
126+
127+
// write rss feed to a file
128+
err = os.WriteFile("rss_feed.xml", output, 0644) // TODO don't hard code file name
129+
if err != nil {
130+
fmt.Println("error writing XML file:", err)
131+
return
132+
}
133+
134+
fmt.Println("rss feed generated successfully!")
135+
}

go.mod

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
module til
2+
3+
go 1.21.6
4+
5+
require github.com/spf13/cobra v1.8.1
6+
7+
require (
8+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
9+
github.com/charmbracelet/lipgloss v1.0.0 // indirect
10+
github.com/charmbracelet/x/ansi v0.4.5 // indirect
11+
github.com/charmbracelet/x/term v0.2.1 // indirect
12+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
13+
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
14+
github.com/mattn/go-isatty v0.0.20 // indirect
15+
github.com/mattn/go-localereader v0.0.1 // indirect
16+
github.com/mattn/go-runewidth v0.0.15 // indirect
17+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
18+
github.com/muesli/cancelreader v0.2.2 // indirect
19+
github.com/muesli/termenv v0.15.2 // indirect
20+
github.com/rivo/uniseg v0.4.7 // indirect
21+
golang.org/x/sync v0.9.0 // indirect
22+
golang.org/x/sys v0.27.0 // indirect
23+
golang.org/x/text v0.3.8 // indirect
24+
)
25+
26+
require (
27+
github.com/charmbracelet/bubbletea v1.2.4
28+
github.com/inconshreveable/mousetrap v1.1.0 // indirect
29+
github.com/russross/blackfriday/v2 v2.1.0
30+
github.com/spf13/pflag v1.0.5 // indirect
31+
)

go.sum

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
2+
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
3+
github.com/charmbracelet/bubbletea v1.2.4 h1:KN8aCViA0eps9SCOThb2/XPIlea3ANJLUkv3KnQRNCE=
4+
github.com/charmbracelet/bubbletea v1.2.4/go.mod h1:Qr6fVQw+wX7JkWWkVyXYk/ZUQ92a6XNekLXa3rR18MM=
5+
github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg=
6+
github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo=
7+
github.com/charmbracelet/x/ansi v0.4.5 h1:LqK4vwBNaXw2AyGIICa5/29Sbdq58GbGdFngSexTdRM=
8+
github.com/charmbracelet/x/ansi v0.4.5/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
9+
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
10+
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
11+
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
12+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
13+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
14+
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
15+
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
16+
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
17+
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
18+
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
19+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
20+
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
21+
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
22+
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
23+
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
24+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
25+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
26+
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
27+
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
28+
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
29+
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
30+
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
31+
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
32+
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
33+
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
34+
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
35+
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
36+
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
37+
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
38+
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
39+
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
40+
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
41+
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
42+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
43+
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
44+
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
45+
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
46+
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
47+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
48+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

main.go

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package main
2+
3+
import "til/cmd"
4+
5+
func main() {
6+
cmd.Execute()
7+
}

rss_feed.xml

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<rss version="2.0">
2+
<channel>
3+
<title>lili til</title>
4+
<link>http://localhost:8000</link>
5+
<description>my posts</description>
6+
<lastBuildDate>Wed, 29 Jan 2025 15:34:19 EST</lastBuildDate>
7+
<item>
8+
<title>heyo.md</title>
9+
<link>http://localhost:8000/heyo.md</link>
10+
<description></description>
11+
<pubDate>Wed, 29 Jan 2025 15:13:47 EST</pubDate>
12+
</item>
13+
<item>
14+
<title>hi.md</title>
15+
<link>http://localhost:8000/hi.md</link>
16+
<description>&lt;h1&gt;til: &lt;TODO: what did you learn?&gt;&lt;/h1&gt;&#xA;&#xA;&lt;!--fill in this section with what you learned!--&gt;&#xA;</description>
17+
<pubDate>Wed, 29 Jan 2025 15:23:19 EST</pubDate>
18+
</item>
19+
<item>
20+
<title>template.md</title>
21+
<link>http://localhost:8000/template.md</link>
22+
<description>&lt;h1&gt;til: &lt;TODO: what did you learn?&gt;&lt;/h1&gt;&#xA;&#xA;&lt;!--fill in this section with what you learned!--&gt;&#xA;</description>
23+
<pubDate>Wed, 29 Jan 2025 15:18:13 EST</pubDate>
24+
</item>
25+
</channel>
26+
</rss>

0 commit comments

Comments
 (0)