1
<?php
2
/**
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information please see
17
 * <http://phing.info>.
18
 */
19

20
/**
21
 * Converts path and classpath information to a specific target OS
22
 * format. The resulting formatted path is placed into the specified property.
23
 *
24
 * @author Siad Ardroumli <siad.ardroumli@gmail.com>
25
 *
26
 * @package phing.tasks.system
27
 */
28
class PathConvert extends Task
29
{
30
    // Members
31
    /**
32
     * Path to be converted
33
     */
34
    private $path = null;
35
    /**
36
     * Reference to path/fileset to convert
37
     *
38
     * @var Reference $refid
39
     */
40
    private $refid = null;
41
    /**
42
     * The target OS type
43
     */
44
    private $targetOS = null;
45
    /**
46
     * Set when targetOS is set to windows
47
     */
48
    private $targetWindows = false;
49
    /**
50
     * Set if we're running on windows
51
     */
52
    public $onWindows = false;
53
    /**
54
     * Set if we should create a new property even if the result is empty
55
     */
56
    private $setonempty = true;
57
    /**
58
     * The property to receive the conversion
59
     */
60
    private $property = null;
61
    /**
62
     * Path prefix map
63
     *
64
     * @var MapEntry[]
65
     */
66
    private $prefixMap = [];
67
    /**
68
     * User override on path sep char
69
     */
70
    private $pathSep = null;
71
    /**
72
     * User override on directory sep char
73
     */
74
    private $dirSep = null;
75

76
    public $from = null;
77
    public $to = null;
78
    private $mapper;
79
    private $preserveDuplicates = false;
80

81
    /**
82
     * constructor
83
     */
84 1
    public function __construct()
85
    {
86 1
        parent::__construct();
87 1
        $this->onWindows = strncasecmp(PHP_OS, 'WIN', 3) === 0;
88
    }
89

90
    /**
91
     * Create a nested PATH element
92
     */
93 1
    public function createPath()
94
    {
95 1
        if ($this->isReference()) {
96 0
            throw $this->noChildrenAllowed();
97
        }
98

99 1
        if ($this->path === null) {
100 1
            $this->path = new Path($this->getProject());
101
        }
102 1
        return $this->path->createPath();
103
    }
104

105

106
    /**
107
     * Create a nested MAP element
108
     *
109
     * @return MapEntry a Map to configure
110
     */
111 1
    public function createMap()
112
    {
113 1
        $entry = new MapEntry($this);
114

115 1
        $this->prefixMap[] = $entry;
116

117 1
        return $entry;
118
    }
119

120
    /**
121
     * Set targetos to a platform to one of
122
     * "windows", "unix", "netware", or "os/2"; required unless
123
     * unless pathsep and/or dirsep are specified.
124
     */
125 0
    public function setTargetos($target)
126
    {
127 0
        $this->targetOS = $target;
128 0
        $this->targetWindows = $this->targetOS !== 'unix';
129
    }
130

131
    /**
132
     * Set setonempty
133
     *
134
     * If false, don't set the new property if the result is the empty string.
135
     *
136
     * @param bool $setonempty true or false
137
     */
138 0
    public function setSetonempty($setonempty)
139
    {
140 0
        $this->setonempty = $setonempty;
141
    }
142

143
    /**
144
     * The property into which the converted path will be placed.
145
     */
146 1
    public function setProperty($p)
147
    {
148 1
        $this->property = $p;
149
    }
150

151
    /**
152
     * Adds a reference to a Path, FileSet, DirSet, or FileList defined
153
     * elsewhere.
154
     *
155
     * @param Reference $r
156
     *
157
     * @throws BuildException
158
     */
159 0
    public function setRefid(Reference $r)
160
    {
161 0
        if ($this->path !== null) {
162 0
            throw $this->noChildrenAllowed();
163
        }
164

165 0
        $this->refid = $r;
166
    }
167

168

169
    /**
170
     * Set the default path separator string;
171
     * defaults to current JVM
172
     *
173
     * @param string $sep path separator string
174
     */
175 0
    public function setPathSep($sep)
176
    {
177 0
        $this->pathSep = $sep;
178
    }
179

180

181
    /**
182
     * Set the default directory separator string
183
     *
184
     * @param string $sep directory separator string
185
     */
186 1
    public function setDirSep($sep)
187
    {
188 1
        $this->dirSep = $sep;
189
    }
190

191

192
    /**
193
     * Has the refid attribute of this element been set?
194
     *
195
     * @return true if refid is valid
196
     */
197 1
    public function isReference()
198
    {
199 1
        return $this->refid !== null;
200
    }
201

202

203
    /**
204
     * Do the execution.
205
     *
206
     * @throws BuildException if something is invalid
207
     */
208 1
    public function main()
209
    {
210 1
        $savedPath = $this->path;
211 1
        $savedPathSep = $this->pathSep;// may be altered in validateSetup
212 1
        $savedDirSep = $this->dirSep;// may be altered in validateSetup
213

214
        try {
215
            // If we are a reference, create a Path from the reference
216 1
            if ($this->isReference()) {
217 0
                $this->path = new Path($this->getProject());
218 0
                $this->path = $this->path->createPath();
219

220 0
                $obj = $this->refid->getReferencedObject($this->getProject());
221

222 0
                if ($obj instanceof Path) {
223 0
                    $this->path->setRefid($this->refid);
224 0
                } elseif ($obj instanceof FileSet) {
225 0
                    $fs = $obj;
226

227 0
                    $this->path->addFileset($fs);
228 0
                } elseif ($obj instanceof DirSet) {
229 0
                    $ds = $obj;
230

231 0
                    $this->path->addDirset($ds);
232 0
                } elseif ($obj instanceof FileList) {
233 0
                    $fl = $obj;
234

235 0
                    $this->path->addFilelist($fl);
236
                } else {
237 0
                    throw new BuildException(
238
                        "'refid' does not refer to a "
239
                        . "path, fileset, dirset, or "
240 0
                        . "filelist."
241
                    );
242
                }
243
            }
244

245 1
            $this->validateSetup();// validate our setup
246

247
            // Currently, we deal with only two path formats: Unix and Windows
248
            // And Unix is everything that is not Windows
249
            // (with the exception for NetWare and OS/2 below)
250

251
            // for NetWare and OS/2, piggy-back on Windows, since here and
252
            // in the apply code, the same assumptions can be made as with
253
            // windows - that \\ is an OK separator, and do comparisons
254
            // case-insensitive.
255 1
            $fromDirSep = $this->onWindows ? "\\" : "/";
256

257 1
            $rslt = '';
258

259
            // Get the list of path components in canonical form
260 1
            $elems = $this->path->listPaths($this->isPreserveDuplicates());
261

262 1
            $mapperImpl = $this->mapper === null ? new IdentityMapper() : $this->mapper->getImplementation();
263 1
            foreach ($elems as &$elem) {
264 1
                $mapped = $mapperImpl->main($elem);
265 1
                for ($m = 0; $mapped !== null && $m < count($mapped); ++$m) {
266 1
                    $elem = $mapped[$m];
267
                }
268
            }
269 1
            unset($elem);
270 1
            foreach ($elems as $key => $elem) {
271 1
                $elem = $this->mapElement($elem);// Apply the path prefix map
272

273
                // Now convert the path and file separator characters from the
274
                // current os to the target os.
275

276 1
                if ($key !== 0) {
277 0
                    $rslt .= $this->pathSep;
278
                }
279

280 1
                $rslt .= str_replace($fromDirSep, $this->dirSep, $elem);
281
            }
282

283
            // Place the result into the specified property,
284
            // unless setonempty == false
285 1
            $value = $rslt;
286 1
            if ($this->setonempty) {
287 1
                $this->log(
288 1
                    "Set property " . $this->property . " = " . $value,
289 1
                    Project::MSG_VERBOSE
290
                );
291 1
                $this->getProject()->setNewProperty($this->property, $value);
292
            } else {
293 0
                if ($rslt !== '') {
294 0
                    $this->log(
295 0
                        "Set property " . $this->property . " = " . $value,
296 0
                        Project::MSG_VERBOSE
297
                    );
298 0
                    $this->getProject()->setNewProperty($this->property, $value);
299
                }
300
            }
301 1
        } finally {
302 1
            $this->path = $savedPath;
303 1
            $this->dirSep = $savedDirSep;
304 1
            $this->pathSep = $savedPathSep;
305
        }
306
    }
307

308
    /**
309
     * Apply the configured map to a path element. The map is used to convert
310
     * between Windows drive letters and Unix paths. If no map is configured,
311
     * then the input string is returned unchanged.
312
     *
313
     * @param  string $elem The path element to apply the map to
314
     * @return String Updated element
315
     */
316 1
    private function mapElement($elem)
317
    {
318 1
        $size = count($this->prefixMap);
319

320 1
        if ($size !== 0) {
321
            // Iterate over the map entries and apply each one.
322
            // Stop when one of the entries actually changes the element.
323

324 1
            foreach ($this->prefixMap as $entry) {
325 1
                $newElem = $entry->apply((string) $elem);
326

327
                // Note I'm using "!=" to see if we got a new object back from
328
                // the apply method.
329

330 1
                if ($newElem !== (string) $elem) {
331 1
                    $elem = $newElem;
332 1
                    break;// We applied one, so we're done
333
                }
334
            }
335
        }
336

337 1
        return $elem;
338
    }
339

340
    /**
341
     * @throws BuildException
342
     * @throws IOException
343
     */
344 1
    public function createMapper()
345
    {
346 1
        if ($this->mapper !== null) {
347 0
            throw new BuildException("Cannot define more than one mapper", $this->getLocation());
348
        }
349 1
        $this->mapper = new Mapper($this->project);
350

351 1
        return $this->mapper;
352
    }
353

354
    /**
355
     * Validate that all our parameters have been properly initialized.
356
     *
357
     * @throws BuildException if something is not setup properly
358
     */
359 1
    private function validateSetup()
360
    {
361 1
        if ($this->path === null) {
362 0
            throw new BuildException("You must specify a path to convert");
363
        }
364

365
        // Determine the separator strings.  The dirsep and pathsep attributes
366
        // override the targetOS settings.
367 1
        $dsep = FileUtils::getSeparator();
368 1
        $psep = FileUtils::getPathSeparator();
369

370 1
        if ($this->targetOS !== null) {
371 0
            $psep = $this->targetWindows ? ";" : ":";
372 0
            $dsep = $this->targetWindows ? "\\" : "/";
373
        }
374

375 1
        if ($this->pathSep !== null) {// override with pathsep=
376 0
            $psep = $this->pathSep;
377
        }
378

379 1
        if ($this->dirSep !== null) {// override with dirsep=
380 1
            $dsep = $this->dirSep;
381
        }
382

383 1
        $this->pathSep = $psep;
384 1
        $this->dirSep = $dsep;
385
    }
386

387

388
    /**
389
     * Creates an exception that indicates that this XML element must not have
390
     * child elements if the refid attribute is set.
391
     */
392 0
    private function noChildrenAllowed()
393
    {
394 0
        return new BuildException(
395
            "You must not specify nested <path> "
396 0
            . "elements when using the refid attribute."
397
        );
398
    }
399

400
    /**
401
     * Get the preserveDuplicates.
402
     *
403
     * @return boolean
404
     */
405 1
    public function isPreserveDuplicates(): bool
406
    {
407 1
        return $this->preserveDuplicates;
408
    }
409

410
    /**
411
     * @param bool $preserveDuplicates
412
     */
413 0
    public function setPreserveDuplicates(bool $preserveDuplicates): void
414
    {
415 0
        $this->preserveDuplicates = $preserveDuplicates;
416
    }
417
}

Read our documentation on viewing source code .

Loading