@@ -16,6 +16,11 @@ interface CaptureOptions {
16
16
silent ?: boolean
17
17
}
18
18
19
+ interface DpkgConfig {
20
+ excludes : RegExp [ ] ;
21
+ includes : RegExp [ ] ;
22
+ }
23
+
19
24
async function capture ( cmd : string , options ?: CaptureOptions ) : Promise < string > {
20
25
let output = ''
21
26
@@ -170,6 +175,90 @@ export async function latest_version(version_prefix: string): Promise<string> {
170
175
} )
171
176
}
172
177
178
+ function glob_to_regex ( glob : string ) : RegExp {
179
+ return new RegExp ( glob
180
+ . replace ( / \. / g, '\\.' )
181
+ . replace ( / \* / g, '.*' )
182
+ . replace ( / \? / g, '.' )
183
+ ) ;
184
+ }
185
+
186
+ function list_files_in_dir ( directory : string , files : string [ ] = [ ] ) : string [ ] {
187
+ fs . readdirSync ( directory ) . forEach ( file => {
188
+ const p = path . join ( directory , file ) ;
189
+ if ( fs . statSync ( p ) . isDirectory ( ) ) {
190
+ return list_files_in_dir ( p , files ) ;
191
+ } else {
192
+ return files . push ( p ) ;
193
+ }
194
+ } ) ;
195
+
196
+ return files ;
197
+ }
198
+
199
+ function dpkg_read_config ( ) : DpkgConfig {
200
+ const dpkgConfigFilepath = 'excludes' ;
201
+ const dpkgConfigDirPath = 'excludes.d' ;
202
+
203
+ const configs = list_files_in_dir ( dpkgConfigDirPath , [ dpkgConfigFilepath ] ) ;
204
+
205
+ const dpkgConfig : DpkgConfig = {
206
+ excludes : [ ] ,
207
+ includes : [ ] ,
208
+ } ;
209
+
210
+ configs . forEach ( ( config ) => {
211
+ try {
212
+ const dpkgExcludesFile = fs . readFileSync ( config , 'utf8' ) ;
213
+ dpkgExcludesFile . split ( '\n' ) . forEach ( ( line ) => {
214
+ // Exclude
215
+ const excludePattern = 'path-exclude=' ;
216
+ if ( line . startsWith ( excludePattern ) ) {
217
+ const regex = glob_to_regex ( line . substring ( excludePattern . length ) ) ;
218
+ dpkgConfig . excludes . push ( regex ) ;
219
+ return ;
220
+ }
221
+
222
+ // Include
223
+ const includePattern = 'path-include=' ;
224
+ if ( line . startsWith ( includePattern ) ) {
225
+ const regex = glob_to_regex ( line . substring ( includePattern . length ) ) ;
226
+ dpkgConfig . includes . push ( regex ) ;
227
+ return ;
228
+ }
229
+ } ) ;
230
+ } catch ( err ) {
231
+ core . info ( `dpkg excludes file not available: ${ err } ` ) ;
232
+ }
233
+ } ) ;
234
+
235
+ return dpkgConfig ;
236
+ }
237
+
238
+ function dpkg_is_file_included ( dpkgConfig : DpkgConfig , filepath : string ) : boolean {
239
+ var included = true ;
240
+
241
+ dpkgConfig . excludes . forEach ( ( exclude ) => {
242
+ if ( exclude . test ( filepath ) ) {
243
+ included = false ;
244
+ return ;
245
+ }
246
+ } ) ;
247
+
248
+ if ( included ) {
249
+ return true ;
250
+ }
251
+
252
+ dpkgConfig . includes . forEach ( ( include ) => {
253
+ if ( include . test ( filepath ) ) {
254
+ included = true ;
255
+ return ;
256
+ }
257
+ } ) ;
258
+
259
+ return included ;
260
+ } ;
261
+
173
262
async function run_linux ( ) : Promise < void > {
174
263
try {
175
264
const distro = await lsb_release ( )
@@ -234,10 +323,12 @@ async function run_linux(): Promise<void> {
234
323
core . info ( 'Caching APT packages: ' + dpkg_diff . join ( ', ' ) )
235
324
236
325
for ( const pkg of dpkg_diff ) {
326
+ const dpkgConfig = dpkg_read_config ( ) ;
237
327
const output = await capture ( `sudo dpkg -L ${ pkg } ` , { silent : true } )
238
328
const files : Array < string > = output
239
329
. split ( '\n' )
240
330
. filter ( f => fs . statSync ( f ) . isFile ( ) )
331
+ . filter ( f => dpkg_is_file_included ( dpkgConfig , f ) )
241
332
for ( const f of files ) {
242
333
const dest = path . join ( cache_dir , path . dirname ( f ) )
243
334
await io . mkdirP ( dest )
0 commit comments