28

これは非常に奇妙です。私たちはしばらくそれを理解しようとしてきましたが、実際には意味がありません。

この Web プロジェクトは、次のようなターゲットを持つターゲット ファイルをインポートします。

<Target Name="CSSCheckInternal">
    <ItemGroup>
        <CSSFiles Include="$(MSBuildProjectDirectory)\**\*.css" />
    </ItemGroup>
    <CSSChecker Files="@(CSSFiles)" />
</Target>

現時点では、1 つのブランチが完全に構築されており、必要に応じてタスクを実行しています。しかし、他のブランチは上記のターゲットで失敗しています。

失敗は、@(CSSFiles)アイテムがタスクによって受信されたときに、ITaskItem配列に展開されていないように見えるためです。

タスクは次のように記述されます (FullPath メタデータを取得するところまで):

public class CSSChecker : Task
{
    [Required]
    public ITaskItem[] Files
    {
        get;
        set;
    }

    public override bool Execute()
    {
        string fullFilePath = null;
        if (Files != null)
        {
            foreach (var item in Files)
            {
                fullFilePath = item.GetMetadata("FullPath");
                if(!File.Exists(fullFilePath))
                  throw new InvalidOperationException(
                   string.Format("{0} does not exist", fullFilePath));


        //rest of the code elided

失敗しているビルドは、次のInvalidOperationExceptionように最後の行にスローされます。

ファイルが存在しません: C:\Code\Project\**\*.css

したがって、MSBuild は、Include属性でワイルドカードを展開する代わりに、単に文字列を渡しているように見えるためITaskItem、タスクには 1 つしか作成されません。

ターゲット フォルダーディスク上に存在し、破損したプロジェクト ファイルと動作中のプロジェクト ファイルの唯一の違いは、プロジェクト ファイルのかなり前に含まれる単一のファイルです。

アップデート

は Twitter で Sayed Hashimi に尋ねました( MSBuild の本を書きました)。それを通じて、フォルダーのワイルドカードを取り出してみたところ、**今では機能し始めています。タスクはプロジェクト間で再利用できるようになっているため、これはあまり適していません。しかし、それはこれと関係があるように見えます。

更新終了

MSBuild がワイルドカードを正しく展開しない状況を誰かが知っていれば、それは大きな助けになるでしょう!

4

4 に答える 4

23

私はこれを理解しました-プロジェクトディレクトリのobj\フォルダーを削除する必要があり、突然フォルダーのワイルドカードが再び機能し始めました。

私の状況に対する簡単な答えは、パスが長すぎると、MSBuild のワイルドカード処理コードが完全に失敗し、アイテム グループを構築しないように見えるということです。

ここでの問題は、どうやってそんなに長いパスを作成したかということです。まあ、私はしませんでした。これは、組み込みの Web パブリッシング タスクでした。これを次のように使用します (カスタム デプロイの場合)。

<MSBuild Projects="$(Proj)" Properties="Platform=$(Platform);
 Configuration=$(Configuration);DeployOnBuild=true;PackageAsSingleFile=False;
 AutoParameterizationWebConfigConnectionStrings=False" />

これを行うPackageAsSingleFile=Falseと、web サイトのデプロイ可能ファイルが必要なため、zip のビルドを防ぐために使用します。obj フォルダーでは、次のようなフォルダー構造が得られます。

[Project_Dir]\obj\[configuration]\Package\PackageTemp\[Project Dir]\[output *]

[Project_Dir] がc:\my project\の場合、一時パッケージ ファイルのベース フォルダーは のようになりますc:\my project\obj\debug\Package\PackageTemp\c_c\my project\

ご覧のとおり、これはすでに非常に深いフォルダー構造であり、実際にはプロジェクトは通常、ドライブのルートにある最上位のフォルダーではありません。

この展開方法を使用するいくつかのプロジェクトでobj\、パスが長すぎるためにエクスプローラーまたはコマンド ラインでフォルダーを削除できなくなることがわかりました。これを回避するために私がすること1は、完全なパスを短くしてから削除するために、必要な数の親フォルダーの名前を変更することです。つまり、前の例では、次のように名前を変更します。

c:\my project\obj\1\1\1\1\1

これはうまくいきます。

ご想像のとおり、プロジェクトが十分に深いフォルダーで開始された場合、発行タスク用に生成されたアイテムの最終的なパスは非常に長くなります。VS 内からタスクを使用するだけでは、公開中に実際にエラーが発生することがわかりましたが、Publish上記の方法で MSBuild をシェル化すると、実際にはフォルダーの最大パス制限を何らかの形で回避しているように見えます。これを証明するプロジェクトをすぐにまとめるつもりです。

したがって、私の場合、タスクを書き直して、処理するベースフォルダーを取得し、フォルダーとファイル自体を再帰的に処理して、見つかった「obj」フォルダーを無視する必要がありました。

「除外」属性を使用して obj フォルダー内のファイルを除外しようとしましたが、違いはありませんでした (おそらく、両方が失敗していたためです!)。

于 2013-05-24T15:44:31.697 に答える
8

私は同じ問題を抱えていましたが、それが長いパスにも関連していることを確認できます。私のものは、npm によって管理される node_modules フォルダーにありました。

Andreas がrimrafツールを使用して行ったように、フォルダーの名前を変更しなくても、長いパスを削除できることがわかりました。エラーが発生した場合は、もう一度試す価値があります。

また、興味があるのが実際には真の再帰ではない場合 (たとえば、3 つのフォルダー レベルを含めるためのショートカットとして二重アスタリスク (**) 構文のみを使用している場合)、二重アスタリスク構文を一連の単一のアスタリスク (*) を使用した式。

たとえば、実際に含める必要があるフォルダが 3 レベルしかないと仮定すると、これを入れ替えることができます...

C:\**\*.*

...このため。

C:\*\*.*
C:\*\*\*.*
C:\*\*\*\*.*
于 2015-07-27T10:56:17.057 に答える
5

この問題は、再帰検索内のいずれかのパスが より長い場合にのみ発生しますMAX_PATH。これを確認するには、エクスプローラーで最も深いパスにディレクトリを作成しようとすると、パスが長すぎてディレクトリを作成できないというエラーが表示されます。または、この問題を再現したい場合はCreateFileW()、拡張\\\?\パス構文を使用して、最大パスよりも長いパスを作成してください。

FindNextFile()procmon でパスが長すぎるというエラーが表示されることはないため、MsBuild は再度呼び出す前に内部で長さをチェックする必要があります。パスが長すぎる前に 1 レベル上がると、単純に期待どおりの が取得されERROR_NO_MORE_FILES、検索ハンドルが閉じられますが、次のレベルを下げることさえ試みられません。これが発生すると、MsBuild はエラーなしで列挙を放棄します!

于 2014-04-02T09:26:36.980 に答える
3

無効な NTFS ファイルシステム リンクもこの動作を引き起こします。たとえば、含まれているフォルダー内のハード リンクが存在しないパスを指している場合などです。

于 2014-10-08T19:28:02.650 に答える