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