file.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. // SPDX-FileCopyrightText: Adam Evyčędo
  2. //
  3. // SPDX-License-Identifier: AGPL-3.0-or-later
  4. package file
  5. import (
  6. "archive/tar"
  7. "archive/zip"
  8. "io"
  9. "io/ioutil"
  10. "log"
  11. "os"
  12. "path/filepath"
  13. "strings"
  14. "github.com/ulikunitz/xz"
  15. )
  16. func UnzipGtfs(path string, gtfsFile string) error {
  17. r, err := zip.OpenReader(filepath.Join(path, gtfsFile))
  18. if err != nil {
  19. return err
  20. }
  21. defer r.Close()
  22. for _, f := range r.File {
  23. rc, err := f.Open()
  24. if err != nil {
  25. return err
  26. }
  27. defer rc.Close()
  28. txtFile, err := os.Create(filepath.Join(path, f.Name))
  29. if err != nil {
  30. return err
  31. }
  32. defer txtFile.Close()
  33. _, err = io.Copy(txtFile, rc)
  34. if err != nil {
  35. return err
  36. }
  37. }
  38. return nil
  39. }
  40. func DeleteTxtFiles(path string, gtfsFile string) error {
  41. txtFiles, err := ioutil.ReadDir(path)
  42. if err != nil {
  43. return err
  44. }
  45. for _, txtFile := range txtFiles {
  46. if strings.Contains(txtFile.Name(), ".txt") {
  47. err = os.Remove(filepath.Join(path, txtFile.Name()))
  48. if err != nil {
  49. return err
  50. }
  51. }
  52. }
  53. err = os.Remove(filepath.Join(path, gtfsFile))
  54. if err != nil {
  55. return err
  56. }
  57. return nil
  58. }
  59. func DeleteBareFiles(path string) error {
  60. txtFiles, err := ioutil.ReadDir(path)
  61. if err != nil {
  62. return err
  63. }
  64. for _, txtFile := range txtFiles {
  65. if strings.Contains(txtFile.Name(), ".bare") || strings.Contains(txtFile.Name(), ".lua") {
  66. err = os.Remove(filepath.Join(path, txtFile.Name()))
  67. if err != nil {
  68. log.Printf("while removing bare file %s: %v\n", txtFile.Name(), err)
  69. }
  70. }
  71. }
  72. return err
  73. }
  74. func CompressBare(path string, gtfsFile string) error {
  75. trafficFile, err := os.Create(filepath.Join(path, strings.Replace(gtfsFile, ".zip", ".txz", -1)))
  76. if err != nil {
  77. return err
  78. }
  79. defer trafficFile.Close()
  80. xzWriter, err := xz.NewWriter(trafficFile)
  81. if err != nil {
  82. return err
  83. }
  84. defer xzWriter.Close()
  85. tarWriter := tar.NewWriter(xzWriter)
  86. defer tarWriter.Close()
  87. files := []string{"calendar.bare", "ix_stop_codes.bare", "ix_stop_names.bare", "lines.bare", "stops.bare", "trips.bare", "vehicles.bare", "ix_lines.bare", "ix_line_codes.bare", "feed_info.bare", "agencies.bare", "ix_trips.bare", "updates.lua", "vehicles.lua", "alerts.lua"}
  88. optionalFiles := map[string]struct{}{
  89. "updates.lua": {},
  90. "vehicles.lua": {},
  91. "alerts.lua": {},
  92. }
  93. for _, file := range files {
  94. stat, err := os.Stat(filepath.Join(path, file))
  95. if err != nil {
  96. if _, ok := optionalFiles[file]; ok {
  97. log.Printf("while stating %s: %v; ignoring\n", file, err)
  98. continue
  99. }
  100. return err
  101. }
  102. bareFile, err := os.Open(filepath.Join(path, file))
  103. if err != nil {
  104. return err
  105. }
  106. defer bareFile.Close()
  107. hdr := &tar.Header{
  108. Name: file,
  109. Mode: 0600,
  110. Size: stat.Size(),
  111. }
  112. if err := tarWriter.WriteHeader(hdr); err != nil {
  113. return err
  114. }
  115. if _, err := io.Copy(tarWriter, bareFile); err != nil {
  116. return err
  117. }
  118. }
  119. return nil
  120. }
  121. func MoveTraffic(srcName, dstName, path, feedHome string) error {
  122. inputFile, err := os.Open(filepath.Join(path, strings.Replace(srcName, ".zip", ".txz", -1)))
  123. if err != nil {
  124. log.Printf("Couldn't open source file: %s\n", err)
  125. return err
  126. }
  127. outputFile, err := os.Create(filepath.Join(feedHome, dstName))
  128. if err != nil {
  129. inputFile.Close()
  130. log.Printf("Couldn't open dest file: %s\n", err)
  131. return err
  132. }
  133. defer outputFile.Close()
  134. _, err = io.Copy(outputFile, inputFile)
  135. inputFile.Close()
  136. if err != nil {
  137. log.Printf("Writing to output file failed: %s\n", err)
  138. return err
  139. }
  140. err = os.Remove(filepath.Join(path, strings.Replace(srcName, ".zip", ".txz", -1)))
  141. if err != nil {
  142. log.Printf("Failed removing original file: %s\n", err)
  143. return err
  144. }
  145. return nil
  146. }
  147. func ListVersions(path string) ([]string, error) {
  148. versions := []string{}
  149. trafficFiles, err := ioutil.ReadDir(path)
  150. if err != nil {
  151. return nil, err
  152. }
  153. for _, txtFile := range trafficFiles {
  154. if strings.Contains(txtFile.Name(), ".txz") {
  155. versionName := strings.Replace(txtFile.Name(), ".txz", "", 1)
  156. versions = append(versions, versionName)
  157. }
  158. }
  159. return versions, nil
  160. }
  161. func UnpackTraffic(dataHome, feedName string) error {
  162. path := filepath.Join(dataHome, feedName)
  163. files, err := ioutil.ReadDir(path)
  164. if err != nil {
  165. return err
  166. }
  167. unpacked := map[string]bool{}
  168. packed := map[string]bool{}
  169. for _, file := range files {
  170. if strings.Contains(file.Name(), ".txz") {
  171. packed[strings.Replace(file.Name(), ".txz", "", 1)] = true
  172. } else {
  173. unpacked[file.Name()] = true
  174. }
  175. }
  176. for version := range packed {
  177. if !unpacked[version] {
  178. trafficPath := filepath.Join(path, version) + ".txz"
  179. versionPath := filepath.Join(path, version)
  180. err := os.Mkdir(versionPath, 0755)
  181. if err != nil {
  182. return err
  183. }
  184. trafficFile, err := os.Open(trafficPath)
  185. if err != nil {
  186. return err
  187. }
  188. defer trafficFile.Close()
  189. xzReader, err := xz.NewReader(trafficFile)
  190. if err != nil {
  191. return err
  192. }
  193. tarReader := tar.NewReader(xzReader)
  194. for {
  195. hdr, err := tarReader.Next()
  196. if err == io.EOF {
  197. break
  198. }
  199. if err != nil {
  200. return err
  201. }
  202. barePath := filepath.Join(versionPath, hdr.Name)
  203. bareFile, err := os.Create(barePath)
  204. if err != nil {
  205. return err
  206. }
  207. defer bareFile.Close()
  208. if _, err := io.Copy(bareFile, tarReader); err != nil {
  209. return err
  210. }
  211. }
  212. }
  213. }
  214. return nil
  215. }
  216. func CleanOldVersions(path string, validVersions map[string]bool) error {
  217. files, err := ioutil.ReadDir(path)
  218. if err != nil {
  219. return err
  220. }
  221. for _, file := range files {
  222. name := file.Name()
  223. versionString := strings.Replace(name, ".txz", "", 1)
  224. if !validVersions[versionString] {
  225. filePath := filepath.Join(path, name)
  226. os.RemoveAll(filePath)
  227. }
  228. }
  229. return nil
  230. }