timetable-extension #1

Open
fred.boniface wants to merge 163 commits from timetable-extension into main
5 changed files with 195 additions and 3 deletions
Showing only changes of commit 8f0e9759c4 - Show all commits

1
go.mod
View File

@ -23,4 +23,5 @@ require (
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/text v0.16.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

1
go.sum
View File

@ -96,6 +96,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

29
pis/data.go Normal file
View File

@ -0,0 +1,29 @@
package pis
import (
"fmt"
"gopkg.in/yaml.v3"
)
// Process the YAML data to a struct
func processYaml(yamlStr string) (*PisData, error) {
var pis PisData
err := yaml.Unmarshal([]byte(yamlStr), &pis)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal YAML: %v", err)
}
err = deduplicateCodes(&pis)
if err != nil {
return nil, err
}
return &pis, nil
}
// Deduplicate data in place and return error if failed
func deduplicateCodes(pis *PisData) error {
return fmt.Errorf("deduplication logic not present, unable to update")
}

View File

@ -7,3 +7,9 @@ type GiteaReleaseData struct {
Draft bool `json:"draft"`
Prerelease bool `json:"prerelease"`
}
type PisData struct {
Code string `json:"code"`
Stops []string `json:"stops"`
Operator string `json:"operator"`
}

View File

@ -1,11 +1,166 @@
package pis
import (
"archive/tar"
"compress/gzip"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strings"
)
const (
destPath = "/tmp/pis.tar.gz"
extractPath = "/tmp/extract"
)
// Downloads the release tarball, extracts then applies to database
func runUpdate(tarballUrl string) error {
// Download and extract tarball
// load PIS yaml files
// Run code deduplication
err := downloadFile(tarballUrl, destPath)
if err != nil {
return err
}
// Extract to disk
file, err := os.Open(destPath)
if err != nil {
fmt.Printf("Error opening file: %v\n", err)
return err
}
defer file.Close()
if err := extractFiles(file, extractPath); err != nil {
fmt.Printf("Error extracting file: %v\n", err)
return err
}
// Load YAML to string
pisData, err := extractYamlData(extractPath)
if err != nil {
return err
}
// Replace database collection with new data
// Ensure indeces are present
// Cleanup files
cleanupFiles(destPath, extractPath)
return nil
}
// Download the tarball to disk
func downloadFile(url, filepath string) error {
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
out, err := os.Create(filepath)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, resp.Body)
return err
}
// Extract tarball to disk
func extractFiles(gzipStream io.Reader, dest string) error {
uncompressedStream, err := gzip.NewReader(gzipStream)
if err != nil {
return err
}
defer uncompressedStream.Close()
tarReader := tar.NewReader(uncompressedStream)
for {
header, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
filePath := filepath.Join(dest, header.Name)
switch header.Typeflag {
case tar.TypeDir:
if err := os.MkdirAll(filepath.Join(dest, header.Name), 0755); err != nil {
return err
}
case tar.TypeReg:
outFile, err := os.Create(filePath)
if err != nil {
return err
}
if _, err := io.Copy(outFile, tarReader); err != nil {
return err
}
outFile.Close()
default:
fmt.Printf("Unable to handle filetype %c in %s\n", header.Typeflag, header.Name)
}
}
return nil
}
// Return YAML PIS files as a string
func extractYamlData(dir string) (string, error) {
var allContent strings.Builder // Using a string builder to accumulate content
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err // Only returning error since Walk callback doesn't accept string
}
// Check if the path contains 'pis' and has a .yaml or .yml extension
if strings.Contains(path, "/pis/") && !info.IsDir() &&
(strings.HasSuffix(info.Name(), ".yaml") || strings.HasSuffix(info.Name(), ".yml")) {
fmt.Printf("Processing YAML file in 'pis' directory: %s\n", path)
file, err := os.Open(path)
if err != nil {
return fmt.Errorf("failed to open YAML file %s: %v", path, err)
}
defer file.Close()
content, err := io.ReadAll(file)
if err != nil {
return fmt.Errorf("failed to read YAML file %s: %v", path, err)
}
// Accumulate content from each YAML file in 'pis' directory
allContent.Write(content)
allContent.WriteString("\n") // Add a newline between file contents
}
return nil
})
if err != nil {
return "", err
}
// Return the accumulated content as a single string
return allContent.String(), nil
}
// Cleans up downloaded and extracted files
func cleanupFiles(paths ...string) {
for _, path := range paths {
err := os.RemoveAll(path)
if err != nil {
fmt.Printf("Error removing %s: %v\n", path, err)
}
}
}