| 1 | <?php |
|---|
| 2 | /* |
|---|
| 3 | * $Id$ |
|---|
| 4 | * |
|---|
| 5 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|---|
| 6 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|---|
| 7 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|---|
| 8 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|---|
| 9 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|---|
| 10 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|---|
| 11 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|---|
| 12 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|---|
| 13 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|---|
| 14 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|---|
| 15 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|---|
| 16 | * |
|---|
| 17 | * This software consists of voluntary contributions made by many individuals |
|---|
| 18 | * and is licensed under the LGPL. For more information please see |
|---|
| 19 | * <http://phing.info>. |
|---|
| 20 | */ |
|---|
| 21 | |
|---|
| 22 | require_once 'phing/Task.php'; |
|---|
| 23 | include_once 'phing/tasks/system/condition/Condition.php'; |
|---|
| 24 | include_once 'phing/tasks/system/PropertyTask.php'; |
|---|
| 25 | include_once 'phing/util/DirectoryScanner.php'; |
|---|
| 26 | include_once 'phing/util/SourceFileScanner.php'; |
|---|
| 27 | include_once 'phing/mappers/MergeMapper.php'; |
|---|
| 28 | |
|---|
| 29 | /** |
|---|
| 30 | * Sets the given property if the specified target has a timestamp |
|---|
| 31 | * greater than all of the source files. |
|---|
| 32 | * |
|---|
| 33 | * @author Hans Lellelid <hans@xmpl.org> (Phing) |
|---|
| 34 | * @author William Ferguson <williamf@mincom.com> (Ant) |
|---|
| 35 | * @author Hiroaki Nakamura <hnakamur@mc.neweb.ne.jp> (Ant) |
|---|
| 36 | * @author Stefan Bodewig <stefan.bodewig@epost.de> (Ant) |
|---|
| 37 | * @version $Revision$ |
|---|
| 38 | * @package phing.tasks.system |
|---|
| 39 | */ |
|---|
| 40 | class UpToDateTask extends Task implements Condition { |
|---|
| 41 | |
|---|
| 42 | private $_property; |
|---|
| 43 | private $_value; |
|---|
| 44 | private $_sourceFile; |
|---|
| 45 | private $_targetFile; |
|---|
| 46 | private $sourceFileSets = array(); |
|---|
| 47 | private $_filelists = array(); |
|---|
| 48 | |
|---|
| 49 | protected $mapperElement = null; |
|---|
| 50 | |
|---|
| 51 | /** |
|---|
| 52 | * The property to set if the target file is more up-to-date than |
|---|
| 53 | * (each of) the source file(s). |
|---|
| 54 | * |
|---|
| 55 | * @param property the name of the property to set if Target is up-to-date. |
|---|
| 56 | */ |
|---|
| 57 | public function setProperty($property) { |
|---|
| 58 | $this->_property = $property; |
|---|
| 59 | } |
|---|
| 60 | |
|---|
| 61 | /** |
|---|
| 62 | * Get property name |
|---|
| 63 | * @param property the name of the property to set if Target is up-to-date. |
|---|
| 64 | */ |
|---|
| 65 | public function getProperty() { |
|---|
| 66 | return $this->_property; |
|---|
| 67 | } |
|---|
| 68 | |
|---|
| 69 | /** |
|---|
| 70 | * The value to set the named property to if the target file is more |
|---|
| 71 | * up-to-date than (each of) the source file(s). Defaults to 'true'. |
|---|
| 72 | * |
|---|
| 73 | * @param value the value to set the property to if Target is up-to-date |
|---|
| 74 | */ |
|---|
| 75 | public function setValue($value) { |
|---|
| 76 | $this->_value = $value; |
|---|
| 77 | } |
|---|
| 78 | |
|---|
| 79 | /** |
|---|
| 80 | * Returns the value, or "true" if a specific value wasn't provided. |
|---|
| 81 | */ |
|---|
| 82 | private function getValue() { |
|---|
| 83 | return ($this->_value !== null) ? $this->_value : "true"; |
|---|
| 84 | } |
|---|
| 85 | |
|---|
| 86 | /** |
|---|
| 87 | * The file which must be more up-to-date than (each of) the source file(s) |
|---|
| 88 | * if the property is to be set. |
|---|
| 89 | * |
|---|
| 90 | * @param file the file we are checking against. |
|---|
| 91 | */ |
|---|
| 92 | public function setTargetFile($file) { |
|---|
| 93 | if (is_string($file)) { |
|---|
| 94 | $file = new PhingFile($file); |
|---|
| 95 | } |
|---|
| 96 | $this->_targetFile = $file; |
|---|
| 97 | } |
|---|
| 98 | |
|---|
| 99 | /** |
|---|
| 100 | * The file that must be older than the target file |
|---|
| 101 | * if the property is to be set. |
|---|
| 102 | * |
|---|
| 103 | * @param file the file we are checking against the target file. |
|---|
| 104 | */ |
|---|
| 105 | public function setSrcfile($file) { |
|---|
| 106 | if (is_string($file)) { |
|---|
| 107 | $file = new PhingFile($file); |
|---|
| 108 | } |
|---|
| 109 | $this->_sourceFile = $file; |
|---|
| 110 | } |
|---|
| 111 | |
|---|
| 112 | /** |
|---|
| 113 | * Nested <srcfiles> element. |
|---|
| 114 | * |
|---|
| 115 | * @deprecated Deprecated since Phing 2.4.0 |
|---|
| 116 | */ |
|---|
| 117 | public function createSrcfiles() { |
|---|
| 118 | $fs = new FileSet(); |
|---|
| 119 | $this->sourceFileSets[] = $fs; |
|---|
| 120 | return $fs; |
|---|
| 121 | } |
|---|
| 122 | |
|---|
| 123 | /** |
|---|
| 124 | * Nested <fileset> element. |
|---|
| 125 | */ |
|---|
| 126 | public function createFileset() { |
|---|
| 127 | $fs = new FileSet(); |
|---|
| 128 | $this->sourceFileSets[] = $fs; |
|---|
| 129 | return $fs; |
|---|
| 130 | } |
|---|
| 131 | |
|---|
| 132 | /** |
|---|
| 133 | * Supports embedded <filelist> element. |
|---|
| 134 | * @return FileList |
|---|
| 135 | */ |
|---|
| 136 | public function createFileList() { |
|---|
| 137 | $num = array_push($this->_filelists, new FileList()); |
|---|
| 138 | return $this->_filelists[$num-1]; |
|---|
| 139 | } |
|---|
| 140 | |
|---|
| 141 | /** |
|---|
| 142 | * Defines the FileNameMapper to use (nested mapper element). |
|---|
| 143 | */ |
|---|
| 144 | public function createMapper() { |
|---|
| 145 | if ($this->mapperElement !== null) { |
|---|
| 146 | throw new BuildException("Cannot define more than one mapper", |
|---|
| 147 | $this->location); |
|---|
| 148 | } |
|---|
| 149 | $this->mapperElement = new Mapper($this->getProject()); |
|---|
| 150 | return $this->mapperElement; |
|---|
| 151 | } |
|---|
| 152 | |
|---|
| 153 | /** |
|---|
| 154 | * Evaluate (all) target and source file(s) to |
|---|
| 155 | * see if the target(s) is/are up-to-date. |
|---|
| 156 | * @return boolean |
|---|
| 157 | */ |
|---|
| 158 | public function evaluate() { |
|---|
| 159 | if (count($this->sourceFileSets) === 0 && $this->_sourceFile === null) { |
|---|
| 160 | throw new BuildException("At least one srcfile or a nested " |
|---|
| 161 | . "<fileset> element must be set."); |
|---|
| 162 | } |
|---|
| 163 | |
|---|
| 164 | if (count($this->sourceFileSets) > 0 && $this->_sourceFile !== null) { |
|---|
| 165 | throw new BuildException("Cannot specify both the srcfile " |
|---|
| 166 | . "attribute and a nested <fileset> " |
|---|
| 167 | . "element."); |
|---|
| 168 | } |
|---|
| 169 | |
|---|
| 170 | if ($this->_targetFile === null && $this->mapperElement === null) { |
|---|
| 171 | throw new BuildException("The targetfile attribute or a nested " |
|---|
| 172 | . "mapper element must be set."); |
|---|
| 173 | } |
|---|
| 174 | |
|---|
| 175 | // if the target file is not there, then it can't be up-to-date |
|---|
| 176 | if ($this->_targetFile !== null && !$this->_targetFile->exists()) { |
|---|
| 177 | return false; |
|---|
| 178 | } |
|---|
| 179 | |
|---|
| 180 | // if the source file isn't there, throw an exception |
|---|
| 181 | if ($this->_sourceFile !== null && !$this->_sourceFile->exists()) { |
|---|
| 182 | throw new BuildException($this->_sourceFile->getAbsolutePath() |
|---|
| 183 | . " not found."); |
|---|
| 184 | } |
|---|
| 185 | |
|---|
| 186 | $upToDate = true; |
|---|
| 187 | for($i=0,$size=count($this->sourceFileSets); $i < $size && $upToDate; $i++) { |
|---|
| 188 | $fs = $this->sourceFileSets[$i]; |
|---|
| 189 | $ds = $fs->getDirectoryScanner($this->project); |
|---|
| 190 | $upToDate = $upToDate && $this->scanDir($fs->getDir($this->project), |
|---|
| 191 | $ds->getIncludedFiles()); |
|---|
| 192 | } |
|---|
| 193 | |
|---|
| 194 | for($i=0,$size=count($this->_filelists); $i < $size && $upToDate; $i++) { |
|---|
| 195 | $fl = $this->_filelists[$i]; |
|---|
| 196 | $srcFiles = $fl->getFiles($this->project); |
|---|
| 197 | $upToDate = $upToDate && $this->scanDir($fs->getDir($this->project), |
|---|
| 198 | $srcFiles); |
|---|
| 199 | } |
|---|
| 200 | |
|---|
| 201 | if ($this->_sourceFile !== null) { |
|---|
| 202 | if ($this->mapperElement === null) { |
|---|
| 203 | $upToDate = $upToDate && |
|---|
| 204 | ($this->_targetFile->lastModified() >= $this->_sourceFile->lastModified()); |
|---|
| 205 | } else { |
|---|
| 206 | $sfs = new SourceFileScanner($this); |
|---|
| 207 | $upToDate = $upToDate && |
|---|
| 208 | count($sfs->restrict($this->_sourceFile->getAbsolutePath(), |
|---|
| 209 | null, null, |
|---|
| 210 | $this->mapperElement->getImplementation())) === 0; |
|---|
| 211 | } |
|---|
| 212 | } |
|---|
| 213 | return $upToDate; |
|---|
| 214 | } |
|---|
| 215 | |
|---|
| 216 | |
|---|
| 217 | /** |
|---|
| 218 | * Sets property to true if target file(s) have a more recent timestamp |
|---|
| 219 | * than (each of) the corresponding source file(s). |
|---|
| 220 | * @throws BuildException |
|---|
| 221 | */ |
|---|
| 222 | public function main() { |
|---|
| 223 | if ($this->_property === null) { |
|---|
| 224 | throw new BuildException("property attribute is required.", |
|---|
| 225 | $this->location); |
|---|
| 226 | } |
|---|
| 227 | $upToDate = $this->evaluate(); |
|---|
| 228 | if ($upToDate) { |
|---|
| 229 | $property = $this->project->createTask('property'); |
|---|
| 230 | $property->setName($this->getProperty()); |
|---|
| 231 | $property->setValue($this->getValue()); |
|---|
| 232 | $property->setOverride(true); |
|---|
| 233 | $property->main(); // execute |
|---|
| 234 | |
|---|
| 235 | if ($this->mapperElement === null) { |
|---|
| 236 | $this->log("File \"" . $this->_targetFile->getAbsolutePath() |
|---|
| 237 | . "\" is up-to-date.", Project::MSG_VERBOSE); |
|---|
| 238 | } else { |
|---|
| 239 | $this->log("All target files are up-to-date.", |
|---|
| 240 | Project::MSG_VERBOSE); |
|---|
| 241 | } |
|---|
| 242 | } |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | protected function scanDir(PhingFile $srcDir, $files) { |
|---|
| 246 | $sfs = new SourceFileScanner($this); |
|---|
| 247 | $mapper = null; |
|---|
| 248 | $dir = $srcDir; |
|---|
| 249 | if ($this->mapperElement === null) { |
|---|
| 250 | $mm = new MergeMapper(); |
|---|
| 251 | $mm->setTo($this->_targetFile->getAbsolutePath()); |
|---|
| 252 | $mapper = $mm; |
|---|
| 253 | $dir = null; |
|---|
| 254 | } else { |
|---|
| 255 | $mapper = $this->mapperElement->getImplementation(); |
|---|
| 256 | } |
|---|
| 257 | return (count($sfs->restrict($files, $srcDir, $dir, $mapper)) === 0); |
|---|
| 258 | } |
|---|
| 259 | } |
|---|