package main import ( "encoding/csv" "fmt" "html/template" "io" "os" ) const apacheTemplate = ` {{/* Do not edit: generated by tsv2htaccess*/}} {{ range . }} {{- /*gotype: code.osinet.fr/fgm/go_tooling/tsv2htaccess.redirect*/ -}} RewriteRule ^{{ .Clean }}$ {{ .Target }} [L,NC,NE,R=301] {{ end }} ` type redirect struct { Clean, Target string } func main() { var err error if len(os.Args) != 4 { fmt.Fprintf(os.Stderr, ` Syntax: %s source destination prefix Where: - source URL pairs in TSV format - destination Apache .htaccess fragment - prefix Prefix to strip from source URLs in pairs `, os.Args[0]) return } source := os.Args[1] dest := os.Args[2] prefix := os.Args[3] fmt.Fprintf(os.Stderr, "Converting %s to %s, stripping %s\n", source, dest, prefix) var tsv io.ReadCloser tsv, err = os.Open(source) if err != nil { panic(err) } defer tsv.Close() redirects, err := read(tsv, prefix) if err != nil { panic(err) } hta, err := os.Create(dest) if err != nil { panic(err) } defer hta.Close() write(hta, redirects) } func read(tsv io.Reader, expectedPrefix string) ([]redirect, error) { var err error l := len(expectedPrefix) r := csv.NewReader(tsv) r.Comma = '\t' r.FieldsPerRecord = 2 rows, err := r.ReadAll() if err != nil { return nil, err } redirects := make([]redirect, len(rows)) for i, rawRow := range rows { absClean := rawRow[0] actualPrefix := absClean[0:l] if actualPrefix != expectedPrefix { panic(fmt.Errorf("incorrect source prefix: [%s], should be [%s]", actualPrefix, expectedPrefix)) } clean := absClean[l:] redirects[i] = redirect{Clean: clean, Target: rawRow[1]} } return redirects, nil } func write(w io.Writer, redirects []redirect) { tpl := template.Must(template.New("htaccess").Parse(apacheTemplate)) err := tpl.Execute(w, redirects) if err != nil { panic(err) } tpl.Execute(os.Stderr, redirects) }