File: importer.go

package info (click to toggle)
golang-github-wellington-go-libsass 0.9.2%2Bgit20181130.4ef5b9d-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 2,128 kB
  • sloc: cpp: 28,607; ansic: 839; makefile: 44
file content (151 lines) | stat: -rw-r--r-- 2,940 bytes parent folder | download | duplicates (2)
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package libsass

import (
	"errors"
	"io"
	"sync"
	"time"

	"github.com/wellington/go-libsass/libs"
)

var (
	ErrImportNotFound = errors.New("Import unreachable or not found")
)

// Import contains Rel and Abs path and a string of the contents
// representing an import.
type Import struct {
	Body  io.ReadCloser
	bytes []byte
	mod   time.Time
	Prev  string
	Path  string
}

// ModTime returns modification time
func (i Import) ModTime() time.Time {
	return i.mod
}

// Imports is a map with key of "path/to/file"
type Imports struct {
	wg      sync.WaitGroup
	closing chan struct{}
	sync.RWMutex
	m        map[string]Import
	resolver libs.ImportResolver
	idx      int
}

func NewImports() *Imports {
	return &Imports{
		closing: make(chan struct{}),
	}
}

func NewImportsWithResolver(resolver libs.ImportResolver) *Imports {
	return &Imports{
		closing:  make(chan struct{}),
		resolver: resolver,
	}
}

func (i *Imports) Close() {
	close(i.closing)
	i.wg.Wait()
}

// Init sets up a new Imports map
func (p *Imports) Init() {
	p.m = make(map[string]Import)
}

// Add registers an import in the context.Imports
func (p *Imports) Add(prev string, path string, bs []byte) error {
	p.Lock()
	defer p.Unlock()

	// TODO: align these with libsass name "stdin"
	if len(prev) == 0 || prev == "string" {
		prev = "stdin"
	}
	im := Import{
		bytes: bs,
		mod:   time.Now(),
		Prev:  prev,
		Path:  path,
	}

	p.m[prev+":"+path] = im
	return nil
}

// Del removes the import from the context.Imports
func (p *Imports) Del(path string) {
	p.Lock()
	defer p.Unlock()

	delete(p.m, path)
}

// Get retrieves import bytes by path
func (p *Imports) Get(prev, path string) ([]byte, error) {
	p.RLock()
	defer p.RUnlock()
	for _, imp := range p.m {
		if imp.Prev == prev && imp.Path == path {
			return imp.bytes, nil
		}
	}
	return nil, ErrImportNotFound
}

// Update attempts to create a fresh Body from the given path
// Files last modified stamps are compared against import timestamp
func (p *Imports) Update(name string) {
	p.Lock()
	defer p.Unlock()

}

// Len counts the number of entries in context.Imports
func (p *Imports) Len() int {
	return len(p.m)
}

// Bind accepts a SassOptions and adds the registered
// importers in the context.
func (p *Imports) Bind(opts libs.SassOptions) {
	entries := make([]libs.ImportEntry, p.Len())
	i := 0

	p.RLock()
	for _, ent := range p.m {
		bs := ent.bytes
		entries[i] = libs.ImportEntry{
			Parent: ent.Prev,
			Path:   ent.Path,
			Source: string(bs),
		}
		i++
	}
	p.RUnlock()

	resolver := func(url string, prev string) (newURL string, body string, resolved bool) {
		if p.resolver != nil {
			newURL, body, resolved = p.resolver(url, prev)
			if resolved {
				return
			}
		}
		entry, err := libs.GetEntry(entries, prev, url)
		if err == nil {
			return url, entry, true
		}
		return "", "", false
	}

	// set entries somewhere so GC doesn't collect it
	p.idx = libs.BindImporter(opts, resolver)
}