all repos — searchix @ 347521a6dce587e6b51f33608744125d853c7078

Search engine for NixOS, nix-darwin, home-manager and NUR users

internal/fetcher/main.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
package fetcher

import (
	"context"
	"io"
	"os"

	"alin.ovh/x/log"
	"github.com/Southclaws/fault"
	"github.com/Southclaws/fault/fmsg"

	"alin.ovh/searchix/internal/config"
	"alin.ovh/searchix/internal/file"
	"alin.ovh/searchix/internal/index"
)

type Options struct {
	Logger *log.Logger
	Root   *file.Root
}

type FetchedFiles struct {
	Revision io.ReadCloser
	Options  io.ReadCloser
	Packages io.ReadCloser
}

type Fetcher interface {
	FetchIfNeeded(context.Context, *index.SourceMeta) (*FetchedFiles, error)
}

func New(
	source *config.Source,
	opts *Options,
) (fetcher Fetcher, err error) {
	target := source.JoinPath("")
	exists, err := opts.Root.Exists(target)
	if err != nil {
		return nil, fault.Wrap(err, fmsg.With("failed to check if directory exists"))
	}

	if !exists {
		err = opts.Root.MkdirAll(target)
		if err != nil {
			return nil, fault.Wrap(err, fmsg.With("failed to create directory"))
		}
	}

	switch source.Fetcher {
	case config.ChannelNixpkgs:
		fetcher, err = NewNixpkgsChannelFetcher(source, opts)
	case config.Channel:
		fetcher, err = NewChannelFetcher(source, opts)
	case config.Download:
		fetcher, err = NewDownloadFetcher(source, opts)
	default:
		err = fault.Newf("unsupported fetcher type %s", source.Fetcher.String())
	}

	return
}

func Open(
	source *config.Source,
	opts *Options,
) (*FetchedFiles, error) {
	root := opts.Root

	f := &FetchedFiles{}

	rev, err := openIfExists(root, source.JoinPath("revision"))
	if err != nil {
		opts.Logger.Warn("failed to open revision file", "error", err)
	}
	if rev != nil {
		f.Revision = rev
	}

	switch source.Importer {
	case config.Options:
		f.Options, err = root.Open(source.JoinPath("options.json"))
	case config.Packages:
		f.Packages, err = root.Open(source.JoinPath("packages.json"))
	default:
		err = fault.Newf("unsupported importer type %s", source.Importer.String())
	}
	if err != nil {
		return nil, err
	}

	return f, nil
}

func openIfExists(root *file.Root, filename string) (*os.File, error) {
	if exists, err := root.Exists(filename); err != nil {
		return nil, fault.Wrap(err, fmsg.With("failed to check if file exists"))
	} else if !exists {
		return nil, nil
	}

	f, err := root.Open(filename)
	if err != nil {
		return nil, fault.Wrap(err, fmsg.Withf("failed to open file %s", filename))
	}

	return f, nil
}