我一直在努力为我开发的Windows机器编写一个使用PHP的持续集成脚本。
克隆了一个Git存储库后,我无法编写一个脚本来删除它。(.git文件夹和其中的所有内容)。我收到"Permission denied"错误。
似乎断断续续。我试过ping,但失败了,但导致我这个ping票,所以我不是一个人-但使用attrib
的解决方案不适合我。
我终于意识到,它只是需要两次尝试删除其中的一些文件夹和/或文件。最后我的PHP代码是这样的:
<?php
function delTree($dir, $ignore = array()) {
// no need to continue if $dir doesn't exist
if (!file_exists($dir))
return true;
// must not continue if it's a link. trigger an error.
if (is_link($dir)) {
trigger_error("Cannot delete $dir: it's a link.", E_ERROR);
return false;
}
// if it's a file, delete it and return.
if (is_file($dir)) {
return tryUnlink($dir, 2);
}
// it's a directory. so...
// build an array of files/directories within it to delete
$files = array_diff(
scandir($dir), array('.', '..'), $ignore
);
// delete each directory within $dir
foreach ($files as $file) {
delTree("$dir/$file", $ignore);
}
// delete $dir itself
return tryRmdir($dir, 2);
}
function tryUnlink($file, $attempts = 2){
$result = unlink($file);
if (!$result) {
if ($attempts > 1){
return tryUnlink($file, $attempts--);
} else {
trigger_error("Cannot delete file $file", E_ERROR);
return false;
}
}
return true;
}
function tryRmdir($dir, $attempts = 2){
$result = rmdir($dir);
if (!$result) {
if ($attempts > 1){
return tryRmdir($dir, $attempts--);
} else {
trigger_error("Cannot delete directory $dir", E_ERROR);
return false;
}
}
return true;
}
将$attempts
参数设置为2时调用它们解决了所有问题(12小时后)。
我尝试了chmod
这样的事情:将文件转移到0666
,关闭IDE,关闭SourceTree,任何打开的资源管理器窗口,戴上锡纸帽,甚至用命令调用exec()
:
rm -r .git -Force
rmdir .git /s /q
可能还有10个现在就埋在我的仓库里。
原因可能是什么?
函数tryUnlink()
和tryRmdir()
都将导致无限循环(除非它实际上被删除)。请看下面的代码片段+输出。
<?php
function foo ($attempts = 2) {
echo "attempts = $attempts'n";
if ($attempts > 1) {
foo ($attempts--);
} else {
echo "returning with '$attempts <= 1'n";
}
}
foo(2);
输出:attempts = 2
attempts = 2
attempts = 2
[...many many many dupes...]
attempts = 2
attempts = 2
attempts = 2
Segmentation fault (core dumped)
考虑到没有说删除在第二次运行时开始。
在Windows 7(或者可能是Vista?)中,第一次尝试删除目录树失败是很少见的,但不是异常的。我认为这是由于文件系统异步处理删除导致的竞争条件。
正如你已经发现的,你可以通过重试操作来解决这个问题;就我个人而言,我从未见过它连续失败两次,尽管为了安全起见,我通常会让它重试三到四次。