Skip to content

Commit 09883bc

Browse files
v1
1 parent c9962a6 commit 09883bc

29 files changed

Lines changed: 2614 additions & 928 deletions

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2024 ByteSizedMarius
3+
Copyright (c) 2024-26 ByteSizedMarius
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

cmd/cli.go

Lines changed: 81 additions & 190 deletions
Original file line numberDiff line numberDiff line change
@@ -1,231 +1,122 @@
1+
// Exit codes:
2+
// 0 - Success or help displayed
3+
// 1 - Error (invalid args, API failure, etc.)
14
package main
25

36
import (
47
"encoding/json"
58
"flag"
69
"fmt"
7-
"github.com/ByteSizedMarius/rewerse-engineering/pkg"
810
"os"
9-
"strings"
10-
)
1111

12-
func hdl(err error) {
13-
if err != nil {
14-
fmt.Println(err)
15-
os.Exit(1)
16-
}
17-
}
12+
rewerse "github.com/ByteSizedMarius/rewerse-engineering/pkg"
13+
)
1814

1915
func main() {
20-
flag.Usage = func() {
21-
fmt.Println("Usage: rewerse-cli [flags] [subcommand] [subcommand-flags]")
22-
fmt.Println("\nFlags:")
23-
fmt.Println(align("-cert <path>") + "Path to the certificate file (default 'certificate.pem')")
24-
fmt.Println(align("-key <path>") + "Path to the key file (default 'private.key')")
25-
fmt.Println(align("-json") + "Output in JSON format (default false)")
26-
fmt.Println("\nSubcommands:")
27-
fmt.Println(align("marketsearch -query <query>") + "Search for markets")
28-
fmt.Println(align("marketdetails -id <market-id>") + "Get details for a market")
29-
fmt.Println(align("coupons") + "Get coupons")
30-
fmt.Println(align("recalls") + "Get recalls")
31-
fmt.Println(align("discounts -id <market-id> [-raw] [-catGroup]") + "Get discounts")
32-
fmt.Println(align("categories -id <market-id> [-printAll]") + "Get product categories")
33-
fmt.Println(align("products -id <market-id> [-category <category> -search <query>] [-page <page>] [-perPage <productsPerPage>]") + "\n" + align("") + "Get products from a category or by query")
34-
fmt.Println("\nSubcommand-Flags:")
35-
fmt.Println(align("-query <query>") + "Search query. Can be a city, postal code, street, etc.")
36-
fmt.Println(align("-id <market-id>") + "ID of the market or discount. Get it from marketsearch.")
37-
fmt.Println(align("-raw") + "Whether you want raw output format (directly from the API) or parsed.")
38-
fmt.Println(align("-catGroup") + "Group by product category instead of rewe-app category")
39-
fmt.Println(align("-printAll") + "Print all available product categories (very many)")
40-
fmt.Println(align("-category <category>") + "The slug of the category to fetch the products from")
41-
fmt.Println(align("-search <query>") + "Search query for products. Can be any term or EANs for example")
42-
fmt.Println(align("-page <page>") + "Page number for pagination. Starts at 1, default 1. The amount of available pages is included in the output")
43-
fmt.Println(align("-perPage <productsPerPage>") + "Number of products per page. Default 30")
44-
fmt.Println("\nExamples:")
45-
fmt.Println(" rewerse.exe -cert cert.pem -key p.key marketsearch -query Köln")
46-
fmt.Println(" rewerse.exe marketsearch -query Köln")
47-
fmt.Println(" rewerse.exe marketdetails -id 1763153")
48-
fmt.Println(" rewerse.exe discounts -id 1763153")
49-
fmt.Println(" rewerse.exe -json discounts -id 1763153 -raw")
50-
fmt.Println(" rewerse.exe discounts -id 1763153 -catGroup")
51-
fmt.Println(" rewerse.exe categories -id 831002 -printAll")
52-
fmt.Println(" rewerse.exe products -id 831002 -category kueche-haushalt -page 2 -perPage 10")
53-
fmt.Println(" rewerse.exe products -id 831002 -search Karotten")
54-
}
55-
16+
// Global flags
5617
certFile := flag.String("cert", "", "Path to the certificate file")
5718
keyFile := flag.String("key", "", "Path to the key file")
58-
jsonOutput := flag.Bool("json", false, "Output in JSON format (default false)")
19+
jsonOutput := flag.Bool("json", false, "Output in JSON format")
20+
flag.Usage = mainHelp
5921
flag.Parse()
6022

6123
if flag.NArg() == 0 {
62-
flag.Usage()
63-
os.Exit(1)
24+
mainHelp()
25+
os.Exit(0)
6426
}
6527

66-
var crt, key string
67-
if *certFile == "" {
68-
crt = "certificate.pem"
69-
} else {
28+
// Load certificate
29+
crt := "certificate.pem"
30+
key := "private.key"
31+
if *certFile != "" {
7032
crt = *certFile
7133
}
72-
if *keyFile == "" {
73-
key = "private.key"
74-
} else {
34+
if *keyFile != "" {
7535
key = *keyFile
7636
}
7737

78-
var err error
79-
err = rewerse.SetCertificate(crt, key)
80-
if err != nil && *certFile == "" && *keyFile == "" {
81-
fmt.Println("Please provide the paths to the certificate and key files.\n\nrewerse.exe -cert cert.pem -key p.key [...]")
38+
if err := rewerse.SetCertificate(crt, key); err != nil {
39+
if *certFile == "" && *keyFile == "" {
40+
fmt.Fprintln(os.Stderr, "Certificate not found. Use -cert and -key flags or place certificate.pem and private.key in current directory.")
41+
} else {
42+
fmt.Fprintf(os.Stderr, "Error loading certificate: %v\n", err)
43+
}
8244
os.Exit(1)
8345
}
84-
hdl(err)
85-
86-
marketSearchCmd := flag.NewFlagSet("marketsearch", flag.ExitOnError)
87-
marketSearchQuery := marketSearchCmd.String("query", "", "Search query")
88-
89-
marketDetailsCmd := flag.NewFlagSet("marketdetails", flag.ExitOnError)
90-
marketDetailsID := marketDetailsCmd.String("id", "", "ID of the market details")
91-
92-
discountsCmd := flag.NewFlagSet("discounts", flag.ExitOnError)
93-
discountsID := discountsCmd.String("id", "", "Market-ID")
94-
rawOutput := discountsCmd.Bool("raw", false, "Whether to return raw API Data")
95-
groupProduct := discountsCmd.Bool("catGroup", false, "Group by product category instead of app-category")
96-
97-
pcategories := flag.NewFlagSet("categories", flag.ExitOnError)
98-
pcategoriesMarketID := pcategories.String("id", "", "Market-ID")
99-
all := pcategories.Bool("printAll", false, "Print all available product categories")
100-
101-
products := flag.NewFlagSet("products", flag.ExitOnError)
102-
productsMarketID := products.String("id", "", "Market-ID")
103-
productsCategory := products.String("category", "", "Category slug")
104-
productsSearch := products.String("search", "", "Search query")
105-
productsPage := products.Int("page", 0, "Page number")
106-
productsPerPage := products.Int("perPage", 0, "Products per page")
10746

10847
var data any
48+
var err error
49+
10950
switch flag.Arg(0) {
110-
case "marketsearch":
111-
hdl(marketSearchCmd.Parse(flag.Args()[1:]))
112-
if *marketSearchQuery == "" {
113-
fmt.Println("Expected search query")
114-
os.Exit(1)
115-
}
116-
data, err = rewerse.MarketSearch(*marketSearchQuery)
117-
case "marketdetails":
118-
hdl(marketDetailsCmd.Parse(flag.Args()[1:]))
119-
if *marketDetailsID == "" {
120-
fmt.Println("Expected market ID")
121-
os.Exit(1)
51+
case "markets":
52+
data, err = handleMarkets(flag.Args()[1:])
53+
case "products":
54+
data, err = handleProducts(flag.Args()[1:])
55+
case "recipes":
56+
data, err = handleRecipes(flag.Args()[1:], *jsonOutput)
57+
if data == nil && err == nil {
58+
return // already printed
12259
}
123-
data, err = rewerse.GetMarketDetails(*marketDetailsID)
124-
case "coupons":
125-
var oc rewerse.OneScanCoupons
126-
var c rewerse.Coupons
127-
oc, c, err = rewerse.GetCoupons()
128-
data = []any{oc, c}
129-
case "recalls":
130-
data, err = rewerse.GetRecalls()
13160
case "discounts":
132-
hdl(discountsCmd.Parse(flag.Args()[1:]))
133-
if *rawOutput {
134-
data, err = rewerse.GetDiscountsRaw(*discountsID)
135-
*jsonOutput = true
136-
} else {
137-
data, err = rewerse.GetDiscounts(*discountsID)
138-
}
139-
if *groupProduct {
140-
data = data.(rewerse.Discounts).GroupByProductCategory()
141-
}
61+
data, err = handleDiscounts(flag.Args()[1:])
14262
case "categories":
143-
hdl(pcategories.Parse(flag.Args()[1:]))
144-
if *pcategoriesMarketID == "" {
145-
fmt.Println("Expected market ID")
146-
os.Exit(1)
147-
}
148-
149-
var so rewerse.ShopOverview
150-
so, err = rewerse.GetShopOverview(*pcategoriesMarketID)
151-
hdl(err)
152-
153-
if *all && *jsonOutput {
154-
fmt.Println("Cannot print all and output in JSON format (json is all by default)")
155-
return
156-
}
157-
158-
if *all {
159-
fmt.Println(so.StringAll())
160-
return
161-
} else if !*jsonOutput {
162-
fmt.Println(so.String())
163-
return
164-
} else {
165-
data = so.ProductCategories
166-
}
167-
case "products":
168-
hdl(products.Parse(flag.Args()[1:]))
169-
if *productsMarketID == "" {
170-
fmt.Println("Expected market ID")
171-
os.Exit(1)
172-
}
173-
174-
if *productsCategory == "" && *productsSearch == "" {
175-
fmt.Println("Expected category or search query")
176-
os.Exit(1)
177-
}
178-
179-
if *productsCategory != "" && *productsSearch != "" {
180-
fmt.Println("Expected either category or search query, not both")
181-
os.Exit(1)
182-
}
183-
184-
var opts *rewerse.ProductOpts
185-
if *productsPage != 0 {
186-
opts = &rewerse.ProductOpts{
187-
Page: *productsPage,
188-
}
63+
data, err = handleCategories(flag.Args()[1:], *jsonOutput)
64+
if data == nil {
65+
return // already printed
18966
}
190-
191-
if *productsPerPage != 0 {
192-
if opts == nil {
193-
opts = &rewerse.ProductOpts{
194-
ObjectsPerPage: *productsPerPage,
195-
}
196-
} else {
197-
opts.ObjectsPerPage = *productsPerPage
198-
}
199-
}
200-
201-
if *productsCategory != "" {
202-
data, err = rewerse.GetCategoryProducts(*productsMarketID, *productsCategory, opts)
203-
} else {
204-
data, err = rewerse.GetProducts(*productsMarketID, *productsSearch, opts)
205-
}
206-
67+
case "recalls":
68+
data, err = rewerse.GetRecalls()
69+
case "services":
70+
data, err = handleServices(flag.Args()[1:])
20771
default:
208-
fmt.Println("Expected one of the following subcommands:\n- marketsearch\n- marketdetails\n- coupons\n- recalls\n- discounts\n- categories\n- products")
72+
fmt.Fprintf(os.Stderr, "Unknown command: %s\n\n", flag.Arg(0))
73+
mainHelp()
20974
os.Exit(1)
21075
}
21176

212-
hdl(err)
213-
if *jsonOutput {
214-
var bt []byte
215-
bt, err = json.MarshalIndent(data, "", " ")
216-
hdl(err)
217-
data = string(bt)
77+
if err != nil {
78+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
79+
os.Exit(1)
21880
}
219-
fmt.Println(data)
220-
}
22181

222-
func align(s string) string {
223-
al := 50
224-
if len(s) > al {
225-
al = 0
82+
if *jsonOutput {
83+
bt, err := json.MarshalIndent(data, "", " ")
84+
if err != nil {
85+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
86+
os.Exit(1)
87+
}
88+
fmt.Println(string(bt))
22689
} else {
227-
al -= len(s)
90+
fmt.Println(data)
22891
}
92+
}
22993

230-
return " " + s + strings.Repeat(" ", al)
94+
func mainHelp() {
95+
fmt.Printf(`Usage: %s [flags] <command> [subcommand] [flags]
96+
97+
Flags:
98+
-cert <path> Certificate file (default: certificate.pem)
99+
-key <path> Key file (default: private.key)
100+
-json Output as JSON
101+
102+
Commands:
103+
markets Search and get market details
104+
products Search, browse, and get product info
105+
recipes Search and browse recipes
106+
discounts Get market discounts
107+
categories Get product categories
108+
recalls Get product recalls
109+
services Get service portfolio by zip
110+
111+
Examples:
112+
%s markets search -query Köln
113+
%s products search -market 831002 -query Milch
114+
%s products category -market 831002 -slug obst-gemuese
115+
%s recipes search -term Pasta
116+
%s discounts -market 840174
117+
%s categories -market 831002
118+
%s services -zip 50667
119+
120+
Run '%s <command>' for subcommand help.
121+
`, binaryName, binaryName, binaryName, binaryName, binaryName, binaryName, binaryName, binaryName, binaryName)
231122
}

0 commit comments

Comments
 (0)