update scripts

This commit is contained in:
alexchao26
2021-12-01 20:34:10 -05:00
parent 2888e20870
commit b8c031d229
21 changed files with 405 additions and 305 deletions
+82
View File
@@ -0,0 +1,82 @@
// Package aoc gets inputs and prompts from adventofcode.com
package aoc
import (
"context"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"path/filepath"
"strings"
"time"
)
func ParseFlags() (day, year int, cookie string) {
today := time.Now()
flag.IntVar(&day, "day", today.Day(), "day number to fetch, 1-25")
flag.IntVar(&year, "year", today.Year(), "AOC year")
// defaults to env variable
flag.StringVar(&cookie, "cookie", os.Getenv("AOC_SESSION_COOKIE"), "AOC session cookie")
flag.Parse()
if day > 25 || day < 1 {
log.Fatalf("day out of range: %d", day)
}
if year < 2015 {
log.Fatalf("year is before 2015: %d", year)
}
if cookie == "" {
log.Fatalf("no session cookie set on flag or env var (AOC_SESSION_COOKIE)")
}
return day, year, cookie
}
func GetWithAOCCookie(url string, cookie string) []byte {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
log.Fatalf("making request: %s", err)
}
sessionCookie := http.Cookie{
Name: "session",
Value: cookie,
}
req.AddCookie(&sessionCookie)
res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatalf("making request: %s", err)
}
body, err := io.ReadAll(res.Body)
if err != nil {
log.Fatalf("reading response body: %s", err)
}
fmt.Println("response length is", len(body))
// specific error message from AOC site
if strings.HasPrefix(string(body), "Please don't repeatedly") {
log.Fatalf("Repeated request github.com/alexchao26/advent-of-code-go error")
}
return body
}
func WriteToFile(filename string, contents []byte) {
err := os.MkdirAll(filepath.Dir(filename), os.ModePerm)
if err != nil {
log.Fatalf("making directory: %s", err)
}
err = os.WriteFile(filename, contents, os.FileMode(0644))
if err != nil {
log.Fatalf("writing file: %s", err)
}
}
+29
View File
@@ -0,0 +1,29 @@
package aoc
import (
"fmt"
"path/filepath"
"strings"
"github.com/alexchao26/advent-of-code-go/util"
)
func GetInput(day, year int, cookie string) {
fmt.Printf("fetching for day %d, year %d\n", day, year)
// make the request
url := fmt.Sprintf("https://adventofcode.com/%d/day/%d/input", year, day)
body := GetWithAOCCookie(url, cookie)
if strings.HasPrefix(string(body), "Puzzle inputs differ by user") {
panic("'Puzzle inputs differ by user' response")
}
// write to file
filename := filepath.Join(util.Dirname(), "../..", fmt.Sprintf("%d/day%02d/input.txt", year, day))
WriteToFile(filename, body)
fmt.Println("Wrote to file: ", filename)
fmt.Println("Done!")
}
@@ -1,4 +1,4 @@
package main
package aoc
import (
"bytes"
@@ -8,25 +8,22 @@ import (
"golang.org/x/net/html"
"github.com/alexchao26/advent-of-code-go/scripts/fetchers"
"github.com/alexchao26/advent-of-code-go/util"
)
func main() {
// determine day to fetch
day, year, cookie := fetchers.ParseFlags()
fmt.Println("fetching for day", day)
func GetPrompt(day, year int, cookie string) {
fmt.Printf("fetching for day %d, year %d\n", day, year)
// make the request
url := fmt.Sprintf("https://adventofcode.com/%d/day/%d", year, day)
body := fetchers.GetWithAOCCookie(url, cookie)
body := GetWithAOCCookie(url, cookie)
// parse the dang html
prompt := parseHTML(body)
// write to file
filename := filepath.Join(util.Dirname(), "../../../", fmt.Sprintf("%d/day%02d/prompt.md", year, day))
fetchers.WriteToFile(filename, []byte(prompt))
filename := filepath.Join(util.Dirname(), "../../", fmt.Sprintf("%d/day%02d/prompt.md", year, day))
WriteToFile(filename, []byte(prompt))
fmt.Println("Wrote prompt to file: ", filename)
+8
View File
@@ -0,0 +1,8 @@
package main
import "github.com/alexchao26/advent-of-code-go/scripts/aoc"
func main() {
day, year, cookie := aoc.ParseFlags()
aoc.GetInput(day, year, cookie)
}
+8
View File
@@ -0,0 +1,8 @@
package main
import "github.com/alexchao26/advent-of-code-go/scripts/aoc"
func main() {
day, year, cookie := aoc.ParseFlags()
aoc.GetPrompt(day, year, cookie)
}
+16
View File
@@ -0,0 +1,16 @@
package main
import (
"flag"
"time"
"github.com/alexchao26/advent-of-code-go/scripts/skeleton"
)
func main() {
today := time.Now()
day := flag.Int("day", today.Day(), "day number to fetch, 1-25")
year := flag.Int("year", today.Year(), "AOC year")
flag.Parse()
skeleton.Run(*day, *year)
}
-27
View File
@@ -1,27 +0,0 @@
package main
import (
"fmt"
"path/filepath"
"github.com/alexchao26/advent-of-code-go/scripts/fetchers"
"github.com/alexchao26/advent-of-code-go/util"
)
func main() {
// determine day to fetch
day, year, cookie := fetchers.ParseFlags()
fmt.Println("fetching for day", day)
// make the request
url := fmt.Sprintf("https://adventofcode.com/%d/day/%d/input", year, day)
body := fetchers.GetWithAOCCookie(url, cookie)
// write to file
filename := filepath.Join(util.Dirname(), "../../..", fmt.Sprintf("%d/day%02d/input.txt", year, day))
fetchers.WriteToFile(filename, body)
fmt.Println("Wrote to file: ", filename)
fmt.Println("Done!")
}
-81
View File
@@ -1,81 +0,0 @@
package fetchers
import (
"flag"
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"strings"
"time"
)
func panicWrap(err error, str string) {
panic(fmt.Sprintf("%s: %s", str, err))
}
func ParseFlags() (day, year int, cookie string) {
today := time.Now()
flag.IntVar(&day, "day", today.Day(), "day number to fetch, 1-25")
flag.IntVar(&year, "year", today.Year(), "AOC year")
// env variable set via .bash_profile/.zshenv/etc
flag.StringVar(&cookie, "cookie", os.Getenv("AOC_SESSION_COOKIE"), "AOC session cookie")
flag.Parse()
if day > 25 {
panic("day out of range")
}
if cookie == "" {
panic("No session cookie set on flag or env")
}
return day, year, cookie
}
func GetWithAOCCookie(url string, cookie string) []byte {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
panicWrap(err, "making request")
}
sessionCookie := http.Cookie{
Name: "session",
Value: cookie,
}
req.AddCookie(&sessionCookie)
cli := http.Client{
Timeout: time.Second * 10,
}
res, err := cli.Do(req)
if err != nil {
panicWrap(err, "making request")
}
body, err := ioutil.ReadAll(res.Body)
fmt.Println("response length is", len(body))
if strings.HasPrefix(string(body), "Please don't repeatedly") {
panic("Repeated request github.com/alexchao26/advent-of-code-go error")
}
return body
}
func WriteToFile(filename string, contents []byte) {
MakeDir(filepath.Dir(filename))
err := ioutil.WriteFile(filename, contents, os.FileMode(0644))
if err != nil {
panicWrap(err, "writing file")
}
}
func MakeDir(dir string) {
err := os.MkdirAll(dir, os.ModePerm)
if err != nil {
panic(err)
}
}
+63
View File
@@ -0,0 +1,63 @@
// Package skeleton makes skeletons to be filled out with solutions.
package skeleton
import (
"embed"
"fmt"
"log"
"os"
"path/filepath"
"text/template"
"github.com/alexchao26/advent-of-code-go/util"
)
//go:embed tmpls/*.go
var fs embed.FS
// Run makes a skeleton main.go and main_test.go file for the given day and year
func Run(day, year int) {
if day > 25 || day <= 0 {
log.Fatalf("invalid -day value, must be 1 through 25, got %v", day)
}
if year < 2015 {
log.Fatalf("year is before 2015: %d", year)
}
ts, err := template.ParseFS(fs, "tmpls/*.go")
if err != nil {
log.Fatalf("parsing tmpls directory: %s", err)
}
mainFilename := filepath.Join(util.Dirname(), "../../", fmt.Sprintf("%d/day%02d/main.go", year, day))
testFilename := filepath.Join(util.Dirname(), "../../", fmt.Sprintf("%d/day%02d/main_test.go", year, day))
err = os.MkdirAll(filepath.Dir(mainFilename), os.ModePerm)
if err != nil {
log.Fatalf("making directory: %s", err)
}
ensureNotOverwriting(mainFilename)
ensureNotOverwriting(testFilename)
mainFile, err := os.Create(mainFilename)
if err != nil {
log.Fatalf("creating main.go file: %v", err)
}
testFile, err := os.Create(testFilename)
if err != nil {
log.Fatalf("creating main_test.go file: %v", err)
}
ts.ExecuteTemplate(mainFile, "main.go", nil)
ts.ExecuteTemplate(testFile, "main_test.go", nil)
fmt.Printf("templates made for %d-day%d\n", year, day)
}
func ensureNotOverwriting(filename string) {
_, err := os.Stat(filename)
if err == nil {
log.Fatalf("File already exists: %s", filename)
}
}
+5
View File
@@ -0,0 +1,5 @@
1
2
3
4
5
+57
View File
@@ -0,0 +1,57 @@
package main
import (
_ "embed"
"flag"
"fmt"
"strings"
"github.com/alexchao26/advent-of-code-go/cast"
"github.com/alexchao26/advent-of-code-go/util"
)
//go:embed input.txt
var input string
func init() {
// do this in init (not main) so test file has same input
input = strings.TrimRight(input, "\n")
if len(input) == 0 {
panic("empty input.txt file")
}
}
func main() {
var part int
flag.IntVar(&part, "part", 1, "part 1 or 2")
flag.Parse()
fmt.Println("Running part", part)
if part == 1 {
ans := part1(input)
util.CopyToClipboard(fmt.Sprintf("%v", ans))
fmt.Println("Output:", ans)
} else {
ans := part2(input)
util.CopyToClipboard(fmt.Sprintf("%v", ans))
fmt.Println("Output:", ans)
}
}
func part1(input string) int {
parsed := parseInput(input)
_ = parsed
return 0
}
func part2(input string) int {
return 0
}
func parseInput(input string) (ans []int) {
for _, line := range strings.Split(input, "\n") {
ans = append(ans, cast.ToInt(line))
}
return ans
}
+47
View File
@@ -0,0 +1,47 @@
package main
import (
"testing"
)
func Test_part1(t *testing.T) {
tests := []struct {
name string
input string
want int
}{
{
name: "actual",
input: input,
want: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := part1(tt.input); got != tt.want {
t.Errorf("part1() = %v, want %v", got, tt.want)
}
})
}
}
func Test_part2(t *testing.T) {
tests := []struct {
name string
input string
want int
}{
{
name: "actual",
input: input,
want: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := part2(tt.input); got != tt.want {
t.Errorf("part2() = %v, want %v", got, tt.want)
}
})
}
}
-150
View File
@@ -1,150 +0,0 @@
package main
import (
"fmt"
"os"
"path/filepath"
"text/template"
"github.com/alexchao26/advent-of-code-go/scripts/fetchers"
"github.com/alexchao26/advent-of-code-go/util"
)
type TemplateData struct {
Year int
Day string // a string to include the prefixing zero
}
var testTemplateString = `package main
import (
"testing"
)
func Test_part1(t *testing.T) {
tests := []struct {
name string
input string
want int
}{
// {"actual", util.ReadFile("input.txt"), ACTUAL_ANSWER},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := part1(tt.input); got != tt.want {
t.Errorf("part1() = %v, want %v", got, tt.want)
}
})
}
}
func Test_part2(t *testing.T) {
tests := []struct {
name string
input string
want int
}{
// {"actual", util.ReadFile("input.txt"), ACTUAL_ANSWER},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := part2(tt.input); got != tt.want {
t.Errorf("part2() = %v, want %v", got, tt.want)
}
})
}
}
`
var solutionTemplateString = `package main
import (
"flag"
"fmt"
"strings"
"github.com/alexchao26/advent-of-code-go/cast"
"github.com/alexchao26/advent-of-code-go/util"
)
func main() {
var part int
flag.IntVar(&part, "part", 1, "part 1 or 2")
flag.Parse()
fmt.Println("Running part", part)
if part == 1 {
ans := part1(util.ReadFile("./input.txt"))
util.CopyToClipboard(fmt.Sprintf("%v", ans))
fmt.Println("Output:", ans)
} else {
ans := part2(util.ReadFile("./input.txt"))
util.CopyToClipboard(fmt.Sprintf("%v", ans))
fmt.Println("Output:", ans)
}
}
func part1(input string) int {
parsed := parseInput(input)
_ = parsed
return 0
}
func part2(input string) int {
return 0
}
func parseInput(input string) (ans []int) {
for _, line := range strings.Split(input, "\n") {
ans = append(ans, cast.ToInt(l))
}
return ans
}
`
func main() {
day, year, _ := fetchers.ParseFlags()
data := TemplateData{
Year: year,
Day: fmt.Sprintf("%02d", day),
}
testTemp, err := template.New("test-template").Parse(testTemplateString)
if err != nil {
panic(err)
}
solutionTemp, err := template.New("solution-template").Parse(solutionTemplateString)
if err != nil {
panic(err)
}
solutionFilename := filepath.Join(util.Dirname(), "../../", fmt.Sprintf("%d/day%02d/main.go", year, day))
testFilename := filepath.Join(util.Dirname(), "../../", fmt.Sprintf("%d/day%02d/main_test.go", year, day))
fetchers.MakeDir(filepath.Dir(solutionFilename))
EnsureNotOverwriting(solutionFilename)
EnsureNotOverwriting(testFilename)
solutionWriter, err := os.Create(solutionFilename)
if err != nil {
panic(err)
}
testWriter, err := os.Create(testFilename)
if err != nil {
panic(err)
}
// note: data is no longer used, but keeping it for future reference of text/template
solutionTemp.Execute(solutionWriter, data)
testTemp.Execute(testWriter, data)
fmt.Println("templates made")
}
func EnsureNotOverwriting(filename string) {
_, err := os.Stat(filename)
if err == nil {
panic(fmt.Sprintf("File already exists: %s", filename))
}
}