1Path::IsDev(3) User Contributed Perl Documentation Path::IsDev(3)
2
3
4
6 Path::IsDev - Determine if a given Path resembles a development source
7 tree
8
10 version 1.001003
11
13 use Path::IsDev qw(is_dev);
14
15 if( is_dev('/some/path') ) {
16 ...
17 } else {
18 ...
19 }
20
22 This module is more or less a bunch of heuristics for determining if a
23 given path is a development tree root of some kind.
24
25 This has many useful applications, notably ones that require behaviours
26 for "installed" modules to be different to those that are still "in
27 development"
28
30 debug
31 Debug callback.
32
33 To enable debugging:
34
35 export PATH_ISDEV_DEBUG=1
36
37 "is_dev"
38 Using an "import"'ed "is_dev":
39
40 if( is_dev( $path ) ) {
41
42 }
43
44 Though the actual heuristics used will be based on how "import" was
45 called.
46
47 Additionally, you can call
48
49 Path::IsDev::is_dev
50
51 without "import"ing anything, and it will behave exactly the same as if
52 you'd imported it using
53
54 use Path::IsDev qw( is_dev );
55
56 That is, no "set" specification is applicable, so you'll only get the
57 "default".
58
60 Understanding how this module works, is critical to understand where
61 you can use it, and the consequences of using it.
62
63 This module operates on a very simplistic level, and its easy for
64 false-positives to occur.
65
66 There are two types of Heuristics, Postive/Confirming Heuristics, and
67 Negative/Disconfirming Heuristics.
68
69 Positive Heuristics and Negative Heuristics are based solely on the
70 presence of specific marker files in a directory, or special marker
71 directories.
72
73 For instance, the files "META.yml", "Makefile.PL", and "Build.PL" are
74 all Positive Heuristic markers, because their presence often indicates
75 a "root" of a development tree.
76
77 And for instance, the directories "t/", "xt/" and ".git/" are also
78 Positive Heuristic markers, because these structures are common in
79 "perl" development trees, and uncommon in install trees.
80
81 However, these markers sometimes go wrong, for instance, consider you
82 have a "local::lib" or "perlbrew" install in $HOME
83
84 $HOME/
85 $HOME/lib/
86 $HOME/perl5/perls/perl-5.19.3/lib/site_perl/
87
88 Etc.
89
90 Under normal circumstances, neither $HOME nor those 3 paths are
91 considered "dev".
92
93 However, all it takes to cause a false positive, is for somebody to
94 install a "t" or "xt" directory, or a marker file in one of the above
95 directories for path_isdev($dir) to return true.
96
97 This may not be a problem, at least, until you use "Path::FindDev"
98 which combines "Path::IsDev" with recursive up-level traversal.
99
100 $HOME/
101 $HOME/lib/
102 $HOME/perl5/perls/perl-5.19.3/lib/site_perl/
103
104 find_dev('$HOME/perl5/perls/perl-5.19.3/lib/site_perl/') # returns false, because it is not inside a dev directory
105
106 mkdir $HOME/t
107
108 find_dev('$HOME/perl5/perls/perl-5.19.3/lib/site_perl/') # returns $HOME, because $HOME/t exists.
109
110 And it is this kind of problem that usually catches people off guard.
111
112 PATH_ISDEV_DEBUG=1 \
113 perl -Ilib -MPath::FindDev=find_dev \
114 -E "say find_dev(q{/home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl})"
115
116 ...
117 [Path::IsDev=0] + ::Tool::Dzil => 0 : dist.ini does not exist
118 [Path::IsDev=0] + ::Tool::MakeMaker => 0 : Makefile.PL does not exist
119 [Path::IsDev=0] + ::Tool::ModuleBuild => 0 : Build.PL does not exist
120 [Path::IsDev=0] + ::META => 0 : META.json does not exist
121 [Path::IsDev=0] + ::META => 1 : META.yml exists
122 [Path::IsDev=0] + ::META => 1 : /home/kent/perl5/META.yml is a file
123 [Path::IsDev=0] + ::META matched path /home/kent/perl5
124 /home/kent/perl5
125
126 Whoops!.
127
128 [Path::IsDev=0] + ::META => 1 : META.yml exists
129 [Path::IsDev=0] + ::META => 1 : /home/kent/perl5/META.yml is a file
130
131 No wonder!
132
133 rm /home/kent/perl5/META.yml
134
135 PATH_ISDEV_DEBUG=1 \
136 perl -Ilib -MPath::FindDev=find_dev \
137 -E "say find_dev(q{/home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl})"
138
139 ...
140 [Path::IsDev=0] Matching /home/kent/perl5
141 ...
142 [Path::IsDev=0] + ::TestDir => 0 : xt does not exist
143 [Path::IsDev=0] + ::TestDir => 1 : t exists
144 [Path::IsDev=0] + ::TestDir => 1 : /home/kent/perl5/t is a dir
145 [Path::IsDev=0] + ::TestDir matched path /home/kent/perl5
146 /home/kent/perl5
147
148 Double whoops!
149
150 [Path::IsDev=0] + ::TestDir => 1 : t exists
151 [Path::IsDev=0] + ::TestDir => 1 : /home/kent/perl5/t is a dir
152
153 And you could keep doing that until you rule out all the bad heuristics
154 in your tree.
155
156 Or, you could use a negative heuristic.
157
158 touch /home/kent/perl5/.path_isdev_ignore
159
160 PATH_ISDEV_DEBUG=1 \
161 perl -Ilib -MPath::FindDev=find_dev \
162 -E "say find_dev(q{/home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl})"
163 ...
164 [Path::IsDev=0] Matching /home/kent/perl5
165 [Path::IsDev=0] - ::IsDev::IgnoreFile => 1 : .path_isdev_ignore exists
166 [Path::IsDev=0] - ::IsDev::IgnoreFile => 1 : /home/kent/perl5/.path_isdev_ignore is a file
167 [Path::IsDev=0] - ::IsDev::IgnoreFile excludes path /home/kent/perl5
168 [Path::IsDev=0] no match found
169 ...
170 [Path::IsDev=0] Matching /
171 ...
172 [Path::IsDev=0] no match found
173
174 Success!
175
176 [Path::IsDev=0] - ::IsDev::IgnoreFile => 1 : .path_isdev_ignore exists
177 [Path::IsDev=0] - ::IsDev::IgnoreFile => 1 : /home/kent/perl5/.path_isdev_ignore is a file
178
180 Negative Heuristics bundled with this distribution
181 Just remember, a Negative Heuristic excludes the path it is associated
182 with
183
184 • "IsDev::IgnoreFile" - ".path_isdev_ignore"
185
186 Positive Heuristics bundled with this distribution
187 • "Changelog" - Files matching "Changes", "Changelog", and similar,
188 case insensitive, extensions optional.
189
190 • "DevDirMarker" - explicit ".devdir" file to indicate a project
191 root.
192
193 • "META" - "META.yml"/"META.json"
194
195 • "MYMETA" - "MYMETA.yml"/"MYMETA.json"
196
197 • "Makefile" - Any "Makefile" format documented supported by GNU Make
198
199 • "TestDir" - A directory called either "t/" or "xt/"
200
201 • "Tool::DZil" - A "dist.ini" file
202
203 • "Tool::MakeMaker" - A "Makefile.PL" file
204
205 • "Tool::ModuleBuild" - A "Build.PL" file
206
207 • "VCS::Git" - A ".git" directory
208
210 Heuristic Sets Bundled with this distribution
211 • "Basic" - The basic heuristic set that contains most, if not all
212 heuristics.
213
215 Custom Sets
216 "Path::IsDev" has a system of "sets" of Heuristics, in order to allow
217 for pluggable and flexible heuristic types.
218
219 Though, for the vast majority of cases, this is not required.
220
221 use Path::IsDev is_dev => { set => 'Basic' };
222 use Path::IsDev is_dev => { set => 'SomeOtherSet' , -as => 'is_dev_other' };
223
224 Overriding the default set
225 If for whatever reason the "Basic" set is insufficient, or if it false
226 positives on your system for some reason, the "default" set can be
227 overridden.
228
229 export PATH_ISDEV_DEFAULT_SET="SomeOtherSet"
230
231 ...
232 use Path::IsDev qw( is_dev );
233 is_dev('/some/path') # uses SomeOtherSet
234
235 Though this will only take priority in the event the set is not
236 specified during "import"
237
238 If this poses a security concern for the user, then this security hole
239 can be eliminated by declaring the set you want in code:
240
241 export PATH_ISDEV_DEFAULT_SET="SomeOtherSet"
242
243 ...
244 use Path::IsDev is_dev => { set => 'Basic' };
245 is_dev('/some/path') # uses Basic, regardless of ENV
246
248 Its conceivable, than an evil user could construct an evil set,
249 containing arbitrary and vulnerable code, and possibly stash that evil
250 set in a poorly secured privileged users @INC
251
252 And if they managed to achieve that, if they could poison the
253 privileged users %ENV, they could trick the privileged user into
254 executing arbitrary code.
255
256 Though granted, if you can do either of those 2 things, you're probably
257 security vulnerable anyway, and granted, if you could do either of
258 those 2 things you could do much more evil things by the following:
259
260 export PERL5OPT="-MEvil::Module"
261
262 So with that in understanding, saying this modules default utility is
263 "insecure" is mostly a bogus argument.
264
265 And to that effect, this module does nothing to "lock down" that
266 mechanism, and this module encourages you to NOT force a set, unless
267 you NEED to, and strongly suggests that forcing a set for the purpose
268 of security will achieve no real improvement in security, while
269 simultaneously reducing utility.
270
272 Kent Fredric <kentnl@cpan.org>
273
275 This software is copyright (c) 2017 by Kent Fredric
276 <kentfredric@gmail.com>.
277
278 This is free software; you can redistribute it and/or modify it under
279 the same terms as the Perl 5 programming language system itself.
280
281
282
283perl v5.38.0 2023-07-21 Path::IsDev(3)