Skip to content

Commit

Permalink
Added DependSet task. (#757)
Browse files Browse the repository at this point in the history
  • Loading branch information
siad007 authored and mrook committed Jan 2, 2018
1 parent eb3d338 commit 0579070
Show file tree
Hide file tree
Showing 6 changed files with 430 additions and 0 deletions.
1 change: 1 addition & 0 deletions classes/phing/tasks/defaults.properties
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ switch=phing.tasks.system.SwitchTask
basename=phing.tasks.system.Basename
diagnostics=phing.tasks.system.DiagnosticsTask
pathconvert=phing.tasks.system.PathConvert
dependset=phing.tasks.system.DependSet

; "Core" contributed tasks
; -- i.e. no taskdef needed.
Expand Down
244 changes: 244 additions & 0 deletions classes/phing/tasks/system/DependSet.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
<?php
/**
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://phing.info>.
*/

require_once 'phing/tasks/system/MatchingTask.php';

/**
* Examines and removes out of date target files. If any of the target files
* are out of date with respect to any of the source files, all target
* files are removed. This is useful where dependencies cannot be
* computed (for example, dynamically interpreted parameters or files
* that need to stay in synch but are not directly linked) or where
* the phing task in question could compute them but does not.
*
* nested arguments:
* <ul>
* <li>srcfileset (fileset describing the source files to examine)
* <li>srcfilelist (filelist describing the source files to examine)
* <li>targetfileset (fileset describing the target files to examine)
* <li>targetfilelist (filelist describing the target files to examine)
* </ul>
* At least one instance of either a fileset or filelist for both source and
* target are required.
* <p>
* This task will examine each of the source files against each of the target
* files. If any target files are out of date with respect to any of the source
* files, all targets are removed. If any files named in a (src or target)
* filelist do not exist, all targets are removed.
* Hint: If missing files should be ignored, specify them as include patterns
* in filesets, rather than using filelists.
* </p><p>
* This task attempts to optimize speed of dependency checking. It will stop
* after the first out of date file is found and remove all targets, rather
* than exhaustively checking every source vs target combination unnecessarily.
* </p>
*
* @package phing.tasks.system
* @author Siad Ardroumli <siad.ardroumli@gmail.com>
*/
class DependSet extends MatchingTask
{
/** @var FileSet[] $sourceFileSets */
private $sourceFileSets = [];

/** @var FileList[] $sourceFileLists */
private $sourceFileLists = [];

/** @var FileSet[] $targetFileSets */
private $targetFileSets = [];

/** @var FileList[] $targetFileLists */
private $targetFileLists = [];

/**
* Add a set of source files.
* @param FileSet $fs the FileSet to add.
*/
public function addSrcfileset(FileSet $fs)
{
$this->sourceFileSets[] = $fs;
}

/**
* Add a list of source files.
* @param FileList $fl the FileList to add.
*/
public function addSrcfilelist(FileList $fl)
{
$this->sourceFileLists[] = $fl;
}

/**
* Add a set of target files.
* @param FileSet $fs the FileSet to add.
*/
public function addTargetfileset(FileSet $fs)
{
$this->targetFileSets[] = $fs;
}

/**
* Add a list of target files.
* @param FileList $fl the FileList to add.
*/
public function addTargetfilelist(FileList $fl)
{
$this->targetFileLists[] = $fl;
}

/**
* Executes the task.
* @throws BuildException if errors occur.
*/
public function main()
{
if ((count($this->sourceFileSets) === 0) && (count($this->sourceFileLists) === 0)) {
throw new BuildException('At least one <srcfileset> or <srcfilelist>'
. ' element must be set');
}
if ((count($this->targetFileSets) === 0) && (count($this->targetFileLists) === 0)) {
throw new BuildException('At least one <targetfileset> or'
. ' <targetfilelist> element must be set');
}
$now = (new DateTime())->getTimestamp();
/*
We have to munge the time to allow for the filesystem time
granularity.
*/
// $now += FILE_UTILS . getFileTimestampGranularity();

// Grab all the target files specified via filesets:
$allTargets = [];
$oldestTargetTime = 0;
$oldestTarget = null;
foreach ($this->targetFileSets as $targetFS) {
if (!$targetFS->getDir($this->getProject())->exists()) {
// this is the same as if it was empty, no target files found
continue;
}
$targetDS = $targetFS->getDirectoryScanner($this->getProject());
$targetFiles = $targetDS->getIncludedFiles();

foreach ($targetFiles as $targetFile) {

$dest = new PhingFile($targetFS->getDir($this->getProject()), $targetFile);
$allTargets[] = $dest;

if ($dest->lastModified() > $now) {
$this->log('Warning: ' . $targetFile . ' modified in the future.',
Project::MSG_WARN);
}
if ($oldestTarget === null
|| $dest->lastModified() < $oldestTargetTime) {
$oldestTargetTime = $dest->lastModified();
$oldestTarget = $dest;
}
}
}
// Grab all the target files specified via filelists:
$upToDate = true;
foreach ($this->targetFileLists as $targetFL) {
$targetFiles = $targetFL->getFiles($this->getProject());

foreach ($targetFiles as $targetFile) {
$dest = new PhingFile($targetFL->getDir($this->getProject()), $targetFile);
if (!$dest->exists()) {
$this->log($targetFile . ' does not exist.', Project::MSG_VERBOSE);
$upToDate = false;
continue;
}

$allTargets[] = $dest;
if ($dest->lastModified() > $now) {
$this->log('Warning: ' . $targetFile . ' modified in the future.',
Project::MSG_WARN);
}
if ($oldestTarget === null
|| $dest->lastModified() < $oldestTargetTime) {
$oldestTargetTime = $dest->lastModified();
$oldestTarget = $dest;
}
}
}
if ($oldestTarget !== null) {
$this->log($oldestTarget . ' is oldest target file', Project::MSG_VERBOSE);
} else {
// no target files, then we cannot remove any target files and
// skip the following tests right away
$upToDate = false;
}
// Check targets vs source files specified via filelists:
if ($upToDate) {
foreach ($this->sourceFileLists as $sourceFL) {
$sourceFiles = $sourceFL->getFiles($this->getProject());

foreach ($sourceFiles as $sourceFile) {
$src = new PhingFile($sourceFL->getDir($this->getProject()), $sourceFile);

if ($src->lastModified() > $now) {
$this->log('Warning: ' . $sourceFile
. ' modified in the future.', Project::MSG_WARN);
}
if (!$src->exists()) {
$this->log($sourceFile . ' does not exist.',
Project::MSG_VERBOSE);
$upToDate = false;
break 2;
}
if ($src->lastModified() > $oldestTargetTime) {
$upToDate = false;
$this->log($oldestTarget . ' is out of date with respect to '
. $sourceFile, Project::MSG_VERBOSE);
break 2;
}
}
}
}
// Check targets vs source files specified via filesets:
if ($upToDate) {
foreach ($this->sourceFileSets as $sourceFS) {
$sourceDS = $sourceFS->getDirectoryScanner($this->getProject());
$sourceFiles = $sourceDS->getIncludedFiles();

foreach ($sourceFiles as $sourceFile) {
$src = new PhingFile($sourceFS->getDir($this->getProject()), $sourceFile);

if ($src->lastModified() > $now) {
$this->log('Warning: ' . $sourceFile
. ' modified in the future.', Project::MSG_WARN);
}
if ($src->lastModified() > $oldestTargetTime) {
$upToDate = false;
$this->log($oldestTarget . ' is out of date with respect to '
. $sourceFile, Project::MSG_VERBOSE);
break 2;
}
}
}
}
if (!$upToDate) {
$this->log('Deleting all target files. ', Project::MSG_VERBOSE);
foreach ($allTargets as $fileToRemove) {
$this->log('Deleting file ' . $fileToRemove->getAbsolutePath(),
Project::MSG_VERBOSE);
$fileToRemove->delete();
}
}
}
}
58 changes: 58 additions & 0 deletions docs/docbook5/en/source/appendixes/coretasks.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1375,6 +1375,64 @@ verbose="true" failonerror="false" /></programlisting>
</itemizedlist>
</sect2>
</sect1>
<sect1 role="taskdef" xml:id="DependSet">
<title> DependSet</title>
<para>The dependset task compares a set of sources with a set of target files.
If any of the sources has been modified more recently than any of the target files,
all of the target files are removed.</para>
<sect2>
<title>Examples</title>
<programlisting language="xml">&lt;dependset>
&lt;srcfilelist
dir = "${dtd.dir}"
files = "paper.dtd,common.dtd"/>
&lt;srcfilelist
dir = "${xsl.dir}"
files = "common.xsl"/>
&lt;srcfilelist
dir = "${basedir}"
files = "build.xml"/>
&lt;targetfileset
dir = "${output.dir}"
includes = "**/*.html"/>
&lt;/dependset></programlisting>
<para> In this example derived HTML files in the ${output.dir} directory will be removed if any are
out-of-date with respect to:</para>
<itemizedlist>
<listitem>
<para>the DTD of their source XML files</para>
</listitem>
<listitem>
<para>a common DTD (imported by the main DTD)</para>
</listitem>
<listitem>
<para>a subordinate XSLT stylesheet (imported by the main stylesheet), or</para>
</listitem>
<listitem>
<para>the buildfile</para>
</listitem>
</itemizedlist>
<para>If any of the sources in the above example does not exist, all target files will also be removed.
To ignore missing sources instead, use filesets instead of filelists for the sources.</para>
</sect2>
<sect2 role="nestedtags">
<title>Supported Nested Tags</title>
<itemizedlist>
<listitem>
<para><literal><link linkend="FileSet">srcfileset</link></literal></para>
</listitem>
<listitem>
<para><literal><link linkend="FileSet">srcfilelist</link></literal></para>
</listitem>
<listitem>
<para><literal><link linkend="FileSet">targetfileset</link></literal></para>
</listitem>
<listitem>
<para><literal><link linkend="FileSet">targetfilelist</link></literal></para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
<sect1 role="taskdef" xml:id="DiagnosticsTask">
<title>Diagnostics</title>
<para> Runs phing's -diagnostics code inside phing itself.
Expand Down
30 changes: 30 additions & 0 deletions etc/phing-grammar.rng
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@
<ref name="condition"/>
<ref name="copy"/>
<ref name="delete"/>
<ref name="dependset"/>
<ref name="diagnostics"/>
<ref name="dirname"/>
<ref name="echo"/>
Expand Down Expand Up @@ -347,6 +348,22 @@
</element>
</define>

<define name="srcfileset">
<ref name="fileset"/>
</define>

<define name="srcfilelist">
<ref name="filelist"/>
</define>

<define name="targetfileset">
<ref name="fileset"/>
</define>

<define name="targetfilelist">
<ref name="filelist"/>
</define>

<define name="fileset">
<element name="fileset">
<interleave>
Expand Down Expand Up @@ -1030,6 +1047,19 @@
</element>
</define>

<define name="dependset">
<element name="dependset">
<oneOrMore>
<ref name="srcfileset"/>
<ref name="srcfilelist"/>
</oneOrMore>
<oneOrMore>
<ref name="targetfileset"/>
<ref name="targetfilelist"/>
</oneOrMore>
</element>
</define>

<define name="diagnostics">
<element name="diagnostics">
<empty/>
Expand Down
Loading

0 comments on commit 0579070

Please sign in to comment.