@@ -41,6 +41,33 @@ public enum BaseDir {
4141
4242 public sealed interface FileData {
4343
44+ sealed interface RelativeFileData extends FileData {
45+ BaseDir baseDir ();
46+
47+ Stream <Path > resolveRelativePaths (PathLookup pathLookup );
48+
49+ @ Override
50+ default Stream <Path > resolvePaths (PathLookup pathLookup ) {
51+ Objects .requireNonNull (pathLookup );
52+ var relativePaths = resolveRelativePaths (pathLookup );
53+ switch (baseDir ()) {
54+ case CONFIG :
55+ return relativePaths .map (relativePath -> pathLookup .configDir ().resolve (relativePath ));
56+ case DATA :
57+ // multiple data dirs are a pain...we need the combination of relative paths and data dirs
58+ List <Path > paths = new ArrayList <>();
59+ for (var relativePath : relativePaths .toList ()) {
60+ for (var dataDir : pathLookup .dataDirs ()) {
61+ paths .add (dataDir .resolve (relativePath ));
62+ }
63+ }
64+ return paths .stream ();
65+ default :
66+ throw new IllegalArgumentException ();
67+ }
68+ }
69+ }
70+
4471 final class AbsolutePathFileData implements FileData {
4572 private final Path path ;
4673 private final Mode mode ;
@@ -122,14 +149,25 @@ public int hashCode() {
122149 record PathSettingFileData (String setting , Mode mode ) implements FileData {
123150 @ Override
124151 public Stream <Path > resolvePaths (PathLookup pathLookup ) {
125- if (setting .contains ("*" )) {
126- return pathLookup .settingGlobResolver ().apply (setting ).map (Path ::of );
127- }
128- String path = pathLookup .settingResolver ().apply (setting );
129- return path == null ? Stream .of () : Stream .of (Path .of (path ));
152+ return FileData .resolvePathSettings (pathLookup , setting );
130153 }
131154 }
132155
156+ record RelativePathSettingFileData (String setting , BaseDir baseDir , Mode mode ) implements FileData , RelativeFileData {
157+ @ Override
158+ public Stream <Path > resolveRelativePaths (PathLookup pathLookup ) {
159+ return FileData .resolvePathSettings (pathLookup , setting );
160+ }
161+ }
162+
163+ private static Stream <Path > resolvePathSettings (PathLookup pathLookup , String setting ) {
164+ if (setting .contains ("*" )) {
165+ return pathLookup .settingGlobResolver ().apply (setting ).map (Path ::of );
166+ }
167+ String path = pathLookup .settingResolver ().apply (setting );
168+ return path == null ? Stream .of () : Stream .of (Path .of (path ));
169+ }
170+
133171 static FileData ofPath (Path path , Mode mode ) {
134172 assert path .isAbsolute ();
135173 return new AbsolutePathFileData (path , mode );
@@ -144,6 +182,10 @@ static FileData ofPathSetting(String setting, Mode mode) {
144182 return new PathSettingFileData (setting , mode );
145183 }
146184
185+ static FileData ofRelativePathSetting (String setting , BaseDir baseDir , Mode mode ) {
186+ return new RelativePathSettingFileData (setting , baseDir , mode );
187+ }
188+
147189 Stream <Path > resolvePaths (PathLookup pathLookup );
148190
149191 Mode mode ();
@@ -181,15 +223,16 @@ public static FilesEntitlement build(List<Object> paths) {
181223 String relativePathAsString = file .remove ("relative_path" );
182224 String relativeTo = file .remove ("relative_to" );
183225 String pathSetting = file .remove ("path_setting" );
226+ String relativePathSetting = file .remove ("relative_path_setting" );
184227 String modeAsString = file .remove ("mode" );
185228
186229 if (file .isEmpty () == false ) {
187230 throw new PolicyValidationException ("unknown key(s) [" + file + "] in a listed file for files entitlement" );
188231 }
189- int foundKeys = (pathAsString != null ? 1 : 0 ) + (relativePathAsString != null ? 1 : 0 ) + (pathSetting != null ? 1 : 0 );
232+ int foundKeys = (pathAsString != null ? 1 : 0 ) + (relativePathAsString != null ? 1 : 0 ) + (pathSetting != null ? 1 : 0 ) + ( relativePathSetting != null ? 1 : 0 ) + ( modeAsString != null ? 1 : 0 ) ;
190233 if (foundKeys != 1 ) {
191234 throw new PolicyValidationException (
192- "files entitlement must contain one of [path, relative_path, path_setting] for every entry"
235+ "files entitlement must contain one of [path, relative_path, path_setting, relative_path_setting ] for every entry"
193236 );
194237 }
195238
@@ -198,11 +241,15 @@ public static FilesEntitlement build(List<Object> paths) {
198241 }
199242 Mode mode = parseMode (modeAsString );
200243
244+ BaseDir baseDir = null ;
245+ if (relativeTo != null ) {
246+ baseDir = parseBaseDir (relativeTo );
247+ }
248+
201249 if (relativePathAsString != null ) {
202- if (relativeTo == null ) {
250+ if (baseDir == null ) {
203251 throw new PolicyValidationException ("files entitlement with a 'relative_path' must specify 'relative_to'" );
204252 }
205- final BaseDir baseDir = parseBaseDir (relativeTo );
206253
207254 Path relativePath = Path .of (relativePathAsString );
208255 if (relativePath .isAbsolute ()) {
@@ -217,6 +264,11 @@ public static FilesEntitlement build(List<Object> paths) {
217264 filesData .add (FileData .ofPath (path , mode ));
218265 } else if (pathSetting != null ) {
219266 filesData .add (FileData .ofPathSetting (pathSetting , mode ));
267+ } else if (relativePathSetting != null ) {
268+ if (baseDir == null ) {
269+ throw new PolicyValidationException ("files entitlement with a 'relative_path_setting' must specify 'relative_to'" );
270+ }
271+ filesData .add (FileData .ofRelativePathSetting (relativePathSetting , baseDir , mode ));
220272 } else {
221273 throw new AssertionError ("File entry validation error" );
222274 }
0 commit comments