-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathbindings.ts
148 lines (127 loc) · 4.53 KB
/
bindings.ts
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
/*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {Binding, CacheBinding, ConfigTreeBinding, getProvider, getType} from './binding.js'
import * as fs from 'fs'
import * as path from 'path'
import * as util from 'util'
/**
* The name of the environment variable read to determine the bindings filesystem root. Specified by the Kubernetes
* Service Binding Specification: https://github.com/k8s-service-bindings/spec#workload-projection
*/
export const SERVICE_BINDING_ROOT: string = 'SERVICE_BINDING_ROOT'
/**
* Wraps each {@link Binding} in a {@link CacheBinding}.
*
* @param bindings the {@link Binding}s to wrap
* @return the wrapped {@link Binding}s
*/
export function cached(bindings: Binding[]): Binding[] {
return bindings
.map((v) => new CacheBinding(v))
}
/**
* Creates a new collection of {@link Binding}s, using the specified `root`. If the directory does not exist, an
* empty collection is returned.
*
* @param root the root to populate the `Binding`s from
* @return the bindings found in the root
*/
export async function from(root: string): Promise<Binding[]> {
let s
try {
s = await stat(root)
} catch (e: any) {
if (e.code === 'ENOENT') {
return []
}
throw e
}
if (!s.isDirectory()) {
return []
}
const c = await readdir(root);
const d = await Promise.all(c.map((c) => {
const p = path.join(root, c)
return stat(p).then((s) => ({path: p, stats: s}))
}))
return d.reduce((b, c) => {
if (c.stats.isDirectory()) {
b.push(new ConfigTreeBinding(c.path))
}
return b
}, new Array<Binding>())
}
/**
* Creates a new collection of {@link Binding}s using the `$SERVICE_BINDING_ROOT` environment variable to determine the
* file system root. If the `$SERVICE_BINDING_ROOT` environment variables is not set, an empty collection is returned.
* If the directory does not exist, an empty collection is returned.
*
* @return the {@link Binding}s found in `$SERVICE_BINDING_ROOT`
*/
export async function fromServiceBindingRoot(): Promise<Binding[]> {
const path = process.env[SERVICE_BINDING_ROOT]
return path == undefined ? [] : from(path)
}
/**
* Returns a {@link Binding} with a given name. Comparison is case-insensitive.
*
* @param bindings the `Binding`s to find in
* @param name the name of the `Binding` to find
* @return the `Binding` with a given name if it exists, `undefined` otherwise
*/
export function find(bindings: Binding[], name: string): Binding | undefined {
for (const b of bindings) {
if (equalsIgnoreCase(b.getName(), name)) {
return b
}
}
return undefined
}
/**
* Return zero or more {@link Binding}s with a given type and provider. If `type` or `provider` are `undefined, the
* result is not filtered on that argument. Comparisons are case-insensitive.
*
* @param bindings the `Bindings`s to filter
* @param type the type of `Binding` to find
* @param provider the provider of `Binding` to find
* @return the collection of `Binding`s with a given type and provider
*/
export async function filter(bindings: Binding[], type?: string, provider?: string): Promise<Binding[]> {
const d = await Promise.all(bindings.map(async (b) => {
let m = true
if (type != undefined) {
const t = await getType(b)
m = m && equalsIgnoreCase(t, type)
}
if (provider != undefined) {
const p = await getProvider(b)
m = m && p != undefined && equalsIgnoreCase(p, provider)
}
return {binding: b, match: m}
}))
return d.reduce((b, c) => {
if (c.match) {
b.push(c.binding)
}
return b
},
new Array<Binding>())
}
function equalsIgnoreCase(a: string, b: string): boolean {
return a.localeCompare(b, undefined, {sensitivity: 'accent'}) === 0
}
const readdir = util.promisify(fs.readdir)
const stat = util.promisify(fs.stat)