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 | 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" "gitlab.com/tozd/go/errors" ) 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, ) errors.E { if !source.Manpages.Enable { return errors.New("manpages not enabled for this source") } if source.Manpages.Path == "" { return errors.New("manpages repo source path not configured") } url, err := makeManpageURL(source) if err != nil { return errors.WithMessage(err, "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 errors.WithMessage(err, "failed to fetch manpages") } defer r.Close() if err := m.save(r); err != nil { return errors.WithMessage(err, "failed to save manpages") } m.mtime = mtime return nil } // Open loads the manpage URLs from the JSON file func (m *URLMap) Open() errors.E { m.logger.Debug("opening manpages file", "path", m.path) stat, err := os.Stat(m.path) if err != nil { return errors.WithMessagef(err, "failed to stat manpages file: %s", m.path) } data, err := os.ReadFile(m.path) if err != nil { return errors.WithMessage(err, "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 errors.WithMessage(err, "failed to parse manpages JSON") } m.logger.Debug("loaded manpages data", "urls", len(m.urlMap)) return nil } func (m *URLMap) save(r io.Reader) errors.E { m.logger.Debug("saving manpages file", "path", m.path) f, err := os.Create(m.path) if err != nil { return errors.WithMessage(err, "failed to create manpages file") } defer f.Close() if _, err := io.Copy(f, r); err != nil { return errors.WithMessage(err, "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, errors.E) { url, err := source.Repo.GetRawFileURL(source.Manpages.Path) if err != nil { return "", errors.WithMessage(err, "failed to join manpage URL") } return url, nil } |