internal/manpages/manpages.go (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | package manpages import ( "context" "encoding/json" "fmt" "io" "os" "path/filepath" "time" "alin.ovh/searchix/internal/config" "alin.ovh/searchix/internal/fetcher/http" "alin.ovh/x/log" "github.com/Southclaws/fault" "github.com/Southclaws/fault/fmsg" ) const basename = "manpage-urls.json" type URLMap struct { path string mtime time.Time logger *log.Logger urlMap map[string]string } func New(cfg *config.Config, logger *log.Logger) *URLMap { return &URLMap{ path: filepath.Join(cfg.DataPath, basename), logger: logger, } } func (m *URLMap) Update( ctx context.Context, source *config.Source, ) error { if !source.Manpages.Enable { return fault.New("manpages not enabled for this source") } if source.Manpages.Path == "" { return fault.New("manpages repo source path not configured") } url, err := makeManpageURL(source) if err != nil { return fault.Wrap(err, fmsg.With("failed to join manpages URL")) } m.logger.Debug("fetching manpages URL map", "url", url) r, mtime, err := http.FetchFileIfNeeded(ctx, m.logger.Named("http"), m.mtime, url) if err != nil { return fault.Wrap(err, fmsg.With("failed to fetch manpages")) } defer r.Close() if err := m.save(r); err != nil { return fault.Wrap(err, fmsg.With("failed to save manpages")) } m.mtime = mtime return nil } // Open loads the manpage URLs from the JSON file func (m *URLMap) Open() error { m.logger.Debug("opening manpages file", "path", m.path) stat, err := os.Stat(m.path) if err != nil { return fault.Wrap(err, fmsg.Withf("failed to stat manpages file: %s", m.path)) } data, err := os.ReadFile(m.path) if err != nil { return fault.Wrap(err, fmsg.With("failed to read manpages file")) } m.mtime = stat.ModTime() m.urlMap = make(map[string]string) if err := json.Unmarshal(data, &m.urlMap); err != nil { return fault.Wrap(err, fmsg.With("failed to parse manpages JSON")) } m.logger.Debug("loaded manpages data", "urls", len(m.urlMap)) return nil } func (m *URLMap) save(r io.Reader) error { m.logger.Debug("saving manpages file", "path", m.path) f, err := os.Create(m.path) if err != nil { return fault.Wrap(err, fmsg.With("failed to create manpages file")) } defer f.Close() if _, err := io.Copy(f, r); err != nil { return fault.Wrap(err, fmsg.With("failed to write manpages file")) } return nil } func (m *URLMap) Get(section string, page string) (string, bool) { key := fmt.Sprintf("%s(%s)", page, section) m.logger.Debug("getting manpage URL", "key", key) url, ok := m.urlMap[key] if !ok { return "", false } return url, true } func makeManpageURL(source *config.Source) (string, error) { url, err := source.Repo.GetRawFileURL(source.Manpages.Path) if err != nil { return "", fault.Wrap(err, fmsg.With("failed to join manpage URL")) } return url, nil } |