2011-07-20 2 views
1

J'exécute la commande suivante dans un répertoire racine d'un référentiel Mercurial. Je veux supprimer tous les fichiers et dossiers commençant par « .hg »:PowerShell remove-item réussit mais génère une exception

gci -rec -filter ".hg*" | remove-item -recurse -force 

La chose étrange est que cela fonctionne réellement, mais produit encore l'exception suivante:

Get-ChildItem : Could not find a part of the path 'C:\temp\WSCopyTest\MyCompany.Services.DaftPunk\.hg\'. 
At line:1 char:4 
+ gci <<<< -rec -filter ".hg*" | remove-item -recurse -force 
    + CategoryInfo   : ReadError: (C:\temp\WSCopyT...es.DaftPunk\.hg:String) [Get-ChildItem], DirectoryNotFoundException 
    + FullyQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand 

Parce que l'exception est jeté par Get-ChildItem, je soupçonne que ma compréhension de la pipelining dans PowerShell est défectueuse. Presque comme Get-ChildItem trouve un élément, le passe à l'applet de commande suivante dans le pipeline, puis cherche le suivant? Est-ce ainsi que ça fonctionne?

Ce qui suit était censé être un script qui reproduire le problème, mais, sur la même machine, il fonctionne parfaitement:

$repoRoot = "C:\Temp\HgDeleteTest\MyRepo" 
remove-item $repoRoot -recurse -force 
md $repoRoot 
pushd $repoRoot 
hg.exe init 
add-content ShouldBeLeftBehind.txt "This is some text in a file that should be left behind once the various .hg files/directories are removed." 
add-content .hgignore syntax:glob 
add-content .hgignore *.dll 
add-content .hgignore *.exe 
hg.exe commit --addremove --message "Building test repository with one commit." 
gci -rec -filter ".hg*" | remove-item -recurse -force 
popd 
+0

Même problème ici où cela fonctionne sur une machine, mais je reçois cette erreur sur un autre. – johntrepreneur

+0

Je suppose que cela pourrait être un problème de version powershell s'il y a 2 ensembles de comportements. – johntrepreneur

Répondre

1

Je fini par séparer la recherche de la suppression. Je crois que mon problème était lié à la façon dont la tuyauterie fonctionne par défaut (c'est-à-dire un élément à la fois) mais je n'ai pas été capable de construire un test pour le vérifier.

Dans tous les cas, les éléments suivants fonctionne très bien:

$hgObjects = gci -rec | ?{ $_.name -like ".hg*" -and $_.name -ne ".hgignore" } 
remove-item $hgObjects -force -recurse 

En utilisant ce style, l'applet de commande remove-item obtient un tableau d'objets trouvés et travaille à travers eux.

Le dossier .hg de mon exemple original ne contenait aucun élément appelé .hg*, donc je ne vois pas ce qui se passait. C'était plus comme si j'essayais de supprimer le dossier deux fois, ce que je trouve très étrange. Je me demande si elle est en fait une manifestation PowerShell de ce comportement standard .NET:

Un recenseur reste valable tant que la collection reste inchangée. Si des modifications sont apportées à la collection, telles que l'ajout, la modification ou la suppression d'éléments , l'énumérateur peut être invalidé et l'appel suivant à MoveNext ou Reset peut lancer une exception InvalidOperationException .Si la collection est modifiée entre MoveNext et Current, Current renvoie l'élément auquel il est défini, même si l'énumérateur est déjà invalidé. (Tiré de http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.getenumerator(v=vs.71).aspx).

+0

Oui, je viens de rencontrer le même problème et j'ai utilisé le même correctif. J'ai remarqué que lorsque je divise get-childitem de remove-item, cela prend beaucoup plus de temps pour commencer à supprimer des éléments. Cela suggère que get-childitem canalise le premier résultat à l'opération suivante (remove-item dans ce cas) dès qu'il est disponible et continue après l'achèvement. –

1

pourrait-il que vous supprimez un dossier en commençant par .hg , qui à son tour contient un fichier commençant par .hg, mais ce fichier n'existe plus?

0

Je m'attends à ce que Antony soit correct - en utilisant le -recurse sur le gci énumérera les fichiers et les répertoires qui correspondent à ".hg *". Le répertoire sera retourné en premier. Ensuite, remove-item supprime d'abord le répertoire, et l'option -force supprime tous les fichiers qu'il contient. Ensuite, il essaye de supprimer les fichiers qui se trouvaient dans ce répertoire et qui correspondent à ".hg *" (qui étaient là quand le gci a fonctionné) mais ils sont partis maintenant. Cela devrait arrêter les erreurs:

gci ".hg*" -recurse | select -expand fullname | sort length -desc | remove-item -force 

Tri des noms complets dans l'ordre décroissant de longueur assure qu'aucun répertoire parent correspondant est supprimé avant que tous les fichiers correspondants dans ce répertoire sont supprimés.

1

Ce qui suit limitera ses suppressions aux fichiers uniquement et exclura les dossiers.

gci -rec -filter ".hg*" | Where {$_.psIsContainer -eq $false} | remove-item -recurse -force 

Ensuite, exécutez à nouveau, en supprimant les dossiers:

gci -rec -filter ".hg*" | Where {$_.psIsContainer -eq $true} | remove-item -recurse -force 
+0

Pourquoi ne pas supprimer les dossiers uniquement? Je ne pense pas que Mercurial génère des fichiers comme ceux-là en dehors des dossiers .hg. – JasonMArcher

Questions connexes