| File: | local/lib/perl5/File/HomeDir.pm | 
| Coverage: | 22.4% | 
| line | stmt | bran | cond | sub | time | code | 
|---|---|---|---|---|---|---|
| 1 | package File::HomeDir; | |||||
| 2 | ||||||
| 3 | # See POD at end for documentation | |||||
| 4 | ||||||
| 5 | 2 2  | 22 4  | use 5.00503; | |||
| 6 | 2 2 2  | 7 0 30  | use strict; | |||
| 7 | 2 2 2  | 5 2 10  | use Carp (); | |||
| 8 | 2 2 2  | 5 1 11  | use Config (); | |||
| 9 | 2 2 2  | 3 2 9  | use File::Spec (); | |||
| 10 | 2 2 2  | 440 3 29  | use File::Which (); | |||
| 11 | ||||||
| 12 | # Globals | |||||
| 13 | 2 2 2  | 7 2 128  | use vars qw{$VERSION @ISA @EXPORT @EXPORT_OK $IMPLEMENTED_BY}; | |||
| 14 | BEGIN { | |||||
| 15 | 2  | 2  | $VERSION = '1.00'; | |||
| 16 | ||||||
| 17 | # Inherit manually | |||||
| 18 | 2  | 5  | require Exporter; | |||
| 19 | 2  | 10  | @ISA = qw{ Exporter }; | |||
| 20 | 2  | 3  | @EXPORT = qw{ home }; | |||
| 21 | 2  | 1305  | @EXPORT_OK = qw{ | |||
| 22 | home | |||||
| 23 | my_home | |||||
| 24 | my_desktop | |||||
| 25 | my_documents | |||||
| 26 | my_music | |||||
| 27 | my_pictures | |||||
| 28 | my_videos | |||||
| 29 | my_data | |||||
| 30 | my_dist_config | |||||
| 31 | my_dist_data | |||||
| 32 | users_home | |||||
| 33 | users_desktop | |||||
| 34 | users_documents | |||||
| 35 | users_music | |||||
| 36 | users_pictures | |||||
| 37 | users_videos | |||||
| 38 | users_data | |||||
| 39 | }; | |||||
| 40 | ||||||
| 41 | # %~ doesn't need (and won't take) exporting, as it's a magic | |||||
| 42 | # symbol name that's always looked for in package 'main'. | |||||
| 43 | } | |||||
| 44 | ||||||
| 45 | # Inlined Params::Util functions | |||||
| 46 | sub _CLASS ($) { | |||||
| 47 | 2  | 68  | (defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s) ? $_[0] : undef; | |||
| 48 | } | |||||
| 49 | sub _DRIVER ($$) { | |||||
| 50 | 2  | 4  | (defined _CLASS($_[0]) and eval "require $_[0];" and ! $@ and $_[0]->isa($_[1]) and $_[0] ne $_[1]) ? $_[0] : undef; | |||
| 51 | } | |||||
| 52 | ||||||
| 53 | # Platform detection | |||||
| 54 | if ( $IMPLEMENTED_BY ) { | |||||
| 55 | # Allow for custom HomeDir classes | |||||
| 56 | # Leave it as the existing value | |||||
| 57 | } elsif ( $^O eq 'MSWin32' ) { | |||||
| 58 | # All versions of Windows | |||||
| 59 | $IMPLEMENTED_BY = 'File::HomeDir::Windows'; | |||||
| 60 | } elsif ( $^O eq 'darwin') { | |||||
| 61 | # 1st: try Mac::SystemDirectory by chansen | |||||
| 62 | if ( eval { require Mac::SystemDirectory; 1 } ) { | |||||
| 63 | $IMPLEMENTED_BY = 'File::HomeDir::Darwin::Cocoa'; | |||||
| 64 | } elsif ( eval { require Mac::Files; 1 } ) { | |||||
| 65 | # 2nd try Mac::Files: Carbon - unmaintained since 2006 except some 64bit fixes | |||||
| 66 | $IMPLEMENTED_BY = 'File::HomeDir::Darwin::Carbon'; | |||||
| 67 | } else { | |||||
| 68 | # 3rd: fallback: pure perl | |||||
| 69 | $IMPLEMENTED_BY = 'File::HomeDir::Darwin'; | |||||
| 70 | } | |||||
| 71 | } elsif ( $^O eq 'MacOS' ) { | |||||
| 72 | # Legacy Mac OS | |||||
| 73 | $IMPLEMENTED_BY = 'File::HomeDir::MacOS9'; | |||||
| 74 | } elsif ( File::Which::which('xdg-user-dir') ) { | |||||
| 75 | # freedesktop unixes | |||||
| 76 | $IMPLEMENTED_BY = 'File::HomeDir::FreeDesktop'; | |||||
| 77 | } else { | |||||
| 78 | # Default to Unix semantics | |||||
| 79 | $IMPLEMENTED_BY = 'File::HomeDir::Unix'; | |||||
| 80 | } | |||||
| 81 | unless ( _DRIVER($IMPLEMENTED_BY, 'File::HomeDir::Driver') ) { | |||||
| 82 | Carp::croak("Missing or invalid File::HomeDir driver $IMPLEMENTED_BY"); | |||||
| 83 | } | |||||
| 84 | ||||||
| 85 | ||||||
| 86 | ||||||
| 87 | ||||||
| 88 | ||||||
| 89 | ##################################################################### | |||||
| 90 | # Current User Methods | |||||
| 91 | ||||||
| 92 | sub my_home { | |||||
| 93 | 2  | 9  | $IMPLEMENTED_BY->my_home; | |||
| 94 | } | |||||
| 95 | ||||||
| 96 | sub my_desktop { | |||||
| 97 | 0  | 0  | $IMPLEMENTED_BY->can('my_desktop') | |||
| 98 | ? $IMPLEMENTED_BY->my_desktop | |||||
| 99 | : Carp::croak("The my_desktop method is not implemented on this platform"); | |||||
| 100 | } | |||||
| 101 | ||||||
| 102 | sub my_documents { | |||||
| 103 | 0  | 0  | $IMPLEMENTED_BY->can('my_documents') | |||
| 104 | ? $IMPLEMENTED_BY->my_documents | |||||
| 105 | : Carp::croak("The my_documents method is not implemented on this platform"); | |||||
| 106 | } | |||||
| 107 | ||||||
| 108 | sub my_music { | |||||
| 109 | 0  | 0  | $IMPLEMENTED_BY->can('my_music') | |||
| 110 | ? $IMPLEMENTED_BY->my_music | |||||
| 111 | : Carp::croak("The my_music method is not implemented on this platform"); | |||||
| 112 | } | |||||
| 113 | ||||||
| 114 | sub my_pictures { | |||||
| 115 | 0  | 0  | $IMPLEMENTED_BY->can('my_pictures') | |||
| 116 | ? $IMPLEMENTED_BY->my_pictures | |||||
| 117 | : Carp::croak("The my_pictures method is not implemented on this platform"); | |||||
| 118 | } | |||||
| 119 | ||||||
| 120 | sub my_videos { | |||||
| 121 | 0  | 0  | $IMPLEMENTED_BY->can('my_videos') | |||
| 122 | ? $IMPLEMENTED_BY->my_videos | |||||
| 123 | : Carp::croak("The my_videos method is not implemented on this platform"); | |||||
| 124 | } | |||||
| 125 | ||||||
| 126 | sub my_data { | |||||
| 127 | 0  | 0  | $IMPLEMENTED_BY->can('my_data') | |||
| 128 | ? $IMPLEMENTED_BY->my_data | |||||
| 129 | : Carp::croak("The my_data method is not implemented on this platform"); | |||||
| 130 | } | |||||
| 131 | ||||||
| 132 | ||||||
| 133 | sub my_dist_data { | |||||
| 134 | 0  | 0  | my $params = ref $_[-1] eq 'HASH' ? pop : {}; | |||
| 135 | 0  | 0  | my $dist = pop or Carp::croak("The my_dist_data method requires an argument"); | |||
| 136 | 0  | 0  | my $data = my_data(); | |||
| 137 | ||||||
| 138 | # If datadir is not defined, there's nothing we can do: bail out | |||||
| 139 | # and return nothing... | |||||
| 140 | 0  | 0  | return undef unless defined $data; | |||
| 141 | ||||||
| 142 | # On traditional unixes, hide the top-level directory | |||||
| 143 | 0  | 0  | my $var = $data eq home() | |||
| 144 | ? File::Spec->catdir( $data, '.perl', 'dist', $dist ) | |||||
| 145 | : File::Spec->catdir( $data, 'Perl', 'dist', $dist ); | |||||
| 146 | ||||||
| 147 | # directory exists: return it | |||||
| 148 | 0  | 0  | return $var if -d $var; | |||
| 149 | ||||||
| 150 | # directory doesn't exist: check if we need to create it... | |||||
| 151 | 0  | 0  | return undef unless $params->{create}; | |||
| 152 | ||||||
| 153 | # user requested directory creation | |||||
| 154 | 0  | 0  | require File::Path; | |||
| 155 | 0  | 0  | File::Path::mkpath( $var ); | |||
| 156 | 0  | 0  | return $var; | |||
| 157 | } | |||||
| 158 | ||||||
| 159 | sub my_dist_config { | |||||
| 160 | 0  | 0  | my $params = ref $_[-1] eq 'HASH' ? pop : {}; | |||
| 161 | 0  | 0  | my $dist = pop or Carp::croak("The my_dist_config method requires an argument"); | |||
| 162 | ||||||
| 163 | # not all platforms support a specific my_config() method | |||||
| 164 | 0  | 0  | my $config = $IMPLEMENTED_BY->can('my_config') | |||
| 165 | ? $IMPLEMENTED_BY->my_config | |||||
| 166 | : $IMPLEMENTED_BY->my_documents; | |||||
| 167 | ||||||
| 168 | # If neither configdir nor my_documents is defined, there's | |||||
| 169 | # nothing we can do: bail out and return nothing... | |||||
| 170 | 0  | 0  | return undef unless defined $config; | |||
| 171 | ||||||
| 172 | # On traditional unixes, hide the top-level dir | |||||
| 173 | 0  | 0  | my $etc = $config eq home() | |||
| 174 | ? File::Spec->catdir( $config, '.perl', $dist ) | |||||
| 175 | : File::Spec->catdir( $config, 'Perl', $dist ); | |||||
| 176 | ||||||
| 177 | # directory exists: return it | |||||
| 178 | 0  | 0  | return $etc if -d $etc; | |||
| 179 | ||||||
| 180 | # directory doesn't exist: check if we need to create it... | |||||
| 181 | 0  | 0  | return undef unless $params->{create}; | |||
| 182 | ||||||
| 183 | # user requested directory creation | |||||
| 184 | 0  | 0  | require File::Path; | |||
| 185 | 0  | 0  | File::Path::mkpath( $etc ); | |||
| 186 | 0  | 0  | return $etc; | |||
| 187 | } | |||||
| 188 | ||||||
| 189 | ||||||
| 190 | ||||||
| 191 | ||||||
| 192 | ##################################################################### | |||||
| 193 | # General User Methods | |||||
| 194 | ||||||
| 195 | sub users_home { | |||||
| 196 | 0  | 0  | $IMPLEMENTED_BY->can('users_home') | |||
| 197 | ? $IMPLEMENTED_BY->users_home( $_[-1] ) | |||||
| 198 | : Carp::croak("The users_home method is not implemented on this platform"); | |||||
| 199 | } | |||||
| 200 | ||||||
| 201 | sub users_desktop { | |||||
| 202 | 0  | 0  | $IMPLEMENTED_BY->can('users_desktop') | |||
| 203 | ? $IMPLEMENTED_BY->users_desktop( $_[-1] ) | |||||
| 204 | : Carp::croak("The users_desktop method is not implemented on this platform"); | |||||
| 205 | } | |||||
| 206 | ||||||
| 207 | sub users_documents { | |||||
| 208 | 0  | 0  | $IMPLEMENTED_BY->can('users_documents') | |||
| 209 | ? $IMPLEMENTED_BY->users_documents( $_[-1] ) | |||||
| 210 | : Carp::croak("The users_documents method is not implemented on this platform"); | |||||
| 211 | } | |||||
| 212 | ||||||
| 213 | sub users_music { | |||||
| 214 | 0  | 0  | $IMPLEMENTED_BY->can('users_music') | |||
| 215 | ? $IMPLEMENTED_BY->users_music( $_[-1] ) | |||||
| 216 | : Carp::croak("The users_music method is not implemented on this platform"); | |||||
| 217 | } | |||||
| 218 | ||||||
| 219 | sub users_pictures { | |||||
| 220 | 0  | 0  | $IMPLEMENTED_BY->can('users_pictures') | |||
| 221 | ? $IMPLEMENTED_BY->users_pictures( $_[-1] ) | |||||
| 222 | : Carp::croak("The users_pictures method is not implemented on this platform"); | |||||
| 223 | } | |||||
| 224 | ||||||
| 225 | sub users_videos { | |||||
| 226 | 0  | 0  | $IMPLEMENTED_BY->can('users_videos') | |||
| 227 | ? $IMPLEMENTED_BY->users_videos( $_[-1] ) | |||||
| 228 | : Carp::croak("The users_videos method is not implemented on this platform"); | |||||
| 229 | } | |||||
| 230 | ||||||
| 231 | sub users_data { | |||||
| 232 | 0  | 0  | $IMPLEMENTED_BY->can('users_data') | |||
| 233 | ? $IMPLEMENTED_BY->users_data( $_[-1] ) | |||||
| 234 | : Carp::croak("The users_data method is not implemented on this platform"); | |||||
| 235 | } | |||||
| 236 | ||||||
| 237 | ||||||
| 238 | ||||||
| 239 | ||||||
| 240 | ||||||
| 241 | ##################################################################### | |||||
| 242 | # Legacy Methods | |||||
| 243 | ||||||
| 244 | # Find the home directory of an arbitrary user | |||||
| 245 | sub home (;$) { | |||||
| 246 | # Allow to be called as a method | |||||
| 247 | 0  | 0  | if ( $_[0] and $_[0] eq 'File::HomeDir' ) { | |||
| 248 | 0  | 0  | shift(); | |||
| 249 | } | |||||
| 250 | ||||||
| 251 | # No params means my home | |||||
| 252 | 0  | 0  | return my_home() unless @_; | |||
| 253 | ||||||
| 254 | # Check the param | |||||
| 255 | 0  | 0  | my $name = shift; | |||
| 256 | 0  | 0  | if ( ! defined $name ) { | |||
| 257 | 0  | 0  | Carp::croak("Can't use undef as a username"); | |||
| 258 | } | |||||
| 259 | 0  | 0  | if ( ! length $name ) { | |||
| 260 | 0  | 0  | Carp::croak("Can't use empty-string (\"\") as a username"); | |||
| 261 | } | |||||
| 262 | ||||||
| 263 | # A dot also means my home | |||||
| 264 | ### Is this meant to mean File::Spec->curdir? | |||||
| 265 | 0  | 0  | if ( $name eq '.' ) { | |||
| 266 | 0  | 0  | return my_home(); | |||
| 267 | } | |||||
| 268 | ||||||
| 269 | # Now hand off to the implementor | |||||
| 270 | 0  | 0  | $IMPLEMENTED_BY->users_home($name); | |||
| 271 | } | |||||
| 272 | ||||||
| 273 | ||||||
| 274 | ||||||
| 275 | ||||||
| 276 | ||||||
| 277 | ##################################################################### | |||||
| 278 | # Tie-Based Interface | |||||
| 279 | ||||||
| 280 | # Okay, things below this point get scary | |||||
| 281 | ||||||
| 282 | CLASS: { | |||||
| 283 | # Make the class for the %~ tied hash: | |||||
| 284 | package File::HomeDir::TIE; | |||||
| 285 | ||||||
| 286 | # Make the singleton object. | |||||
| 287 | # (We don't use the hash for anything, though) | |||||
| 288 | ### THEN WHY MAKE IT??? | |||||
| 289 | my $SINGLETON = bless {}; | |||||
| 290 | ||||||
| 291 | 2  | 2  | sub TIEHASH { $SINGLETON } | |||
| 292 | ||||||
| 293 | sub FETCH { | |||||
| 294 | # Catch a bad username | |||||
| 295 | 0  | unless ( defined $_[1] ) { | ||||
| 296 | 0  | Carp::croak("Can't use undef as a username"); | ||||
| 297 | } | |||||
| 298 | ||||||
| 299 | # Get our homedir | |||||
| 300 | 0  | unless ( length $_[1] ) { | ||||
| 301 | 0  | return File::HomeDir::my_home(); | ||||
| 302 | } | |||||
| 303 | ||||||
| 304 | # Get a named user's homedir | |||||
| 305 | 0  | Carp::carp("The tied %~ hash has been deprecated"); | ||||
| 306 | 0  | return File::HomeDir::home($_[1]); | ||||
| 307 | } | |||||
| 308 | ||||||
| 309 | 0  | sub STORE { _bad('STORE') } | ||||
| 310 | 0  | sub EXISTS { _bad('EXISTS') } | ||||
| 311 | 0  | sub DELETE { _bad('DELETE') } | ||||
| 312 | 0  | sub CLEAR { _bad('CLEAR') } | ||||
| 313 | 0  | sub FIRSTKEY { _bad('FIRSTKEY') } | ||||
| 314 | 0  | sub NEXTKEY { _bad('NEXTKEY') } | ||||
| 315 | ||||||
| 316 | sub _bad ($) { | |||||
| 317 | 0  | Carp::croak("You can't $_[0] with the %~ hash") | ||||
| 318 | } | |||||
| 319 | } | |||||
| 320 | ||||||
| 321 | # Do the actual tie of the global %~ variable | |||||
| 322 | tie %~, 'File::HomeDir::TIE'; | |||||
| 323 | ||||||
| 324 | 1; | |||||
| 325 | ||||||