NuGet将文件复制到项目目录中。

7

我创建了一个.nuspec文件,用于打包一堆.proto文件以供项目之间共享。这很好。不幸的是,为了构建.proto文件,它们需要被实际复制到项目目录中,而不仅仅是被引用。请注意,这是一个.NET Core项目。

目前,我的定义创建了一个包,在使用时引用项目中的文件,但这些文件仍然驻留在原始的.Nuget文件夹中,这不是我真正需要的。

以下是我现在拥有的.nuspec定义:

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
    <metadata>
        <id>GRPCProtoFiles</id>
        <version>1.0.0</version>
        <authors>Author</authors>
        <requireLicenseAcceptance>false</requireLicenseAcceptance>
        <description>.proto files NuGet package.</description>
        <dependencies>
          <dependency id="Google.Protobuf" version="3.14.0"/>
          <dependency id="Grpc" version="2.35.0"/>
        </dependencies>
        <contentFiles>
          <files include="any/any/Protos/**/*.proto" buildAction="None" copyToOutput="false" />
        </contentFiles>
    </metadata>
    <files>
        <file src="**\*.proto" target="contentFiles\any\any\Protos" exclude="google\**" />
    </files>
</package>

我知道目前"构建操作"设置为"无", 但是一旦文件在包安装时落到正确的文件夹中,我可以解决这个问题。如果我尝试将.proto文件的构建操作设置为正确的操作(即Protobuf编译器),那么我会收到错误提示,因为文件不在它们应该在的位置。
我做错了什么?
编辑:
好的,我已经查阅了一些可能发生的情况以及原因。具体来说,这篇回答提供了很多见解。然而我仍然想知道该如何实际操作。现在似乎我想做的事情在NuGet上是不可能实现的,我正在使用错误的工具。但除了这个限制之外,NuGet看起来非常理想 - 它能够从源项目中选择只有.proto文件,并把它们发布,而不是为各种目标系统预先构建的库。
我可以添加一个预构建操作来复制文件到项目目录,但我不知道如何引用源NuGet包文件夹(特别是版本改变的情况下)。你们有任何想法是否这个问题有解决办法?
2个回答

18

我真的了解你的想法。首先,将这些proto文件打包为Build Action None的nupkg。然后在主项目下使用预构建事件来处理来自nupkg的文件。问题是如何使用msbuild属性从nupkg获取文件,因为Net Core项目使用Link属性引用主项目下的文件,而不是将实际nuget文件复制到主项目文件夹中。

在Link属性下,您无法更改该文件的Build Action,因为它实际上不存在于主项目文件夹下,主项目也没有处理该文件的职责。

有两个函数可以解决:

=============================================

函数一

您可以直接在nupkg本身下执行此操作,此后,在构建过程中会自动复制proto文件与nuget包一起。请尝试以下步骤,并且您不应该从安装nuget包的另一个主项目添加任何复制任务。

您必须在nupkg中使用<packages_id>.props/targets文件以获得所需内容。请参阅官方文档

1) 创建名为<packages_id>.props的文件。在您的这边,它应该命名为GRPCProtoFiles.props,这样它才能正常工作。

enter image description here

2)GRPCProtoFiles.props文件中添加以下内容:

<Project>

    <Target Name="CopyFiles" BeforeTargets="Build">
        <ItemGroup>
            <File Include="$(MSBuildThisFileDirectory)..\contentFiles\**\*.*"></File>
        </ItemGroup>
        <Copy SourceFiles="@(File)" DestinationFolder="$(ProjectDir)\Protos"></Copy>
    </Target> 


</Project>

3) 将以下内容添加到GRPCProtoFiles.nuspec文件中,以将props文件包含在nupkg中:

<file src="build\*.props" target="build" />

整个GRPCProtoFiles.nuspec文件应该像这样:

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
    <metadata>
        <id>GRPCProtoFiles</id>
        <version>1.0.0</version>
        <authors>Author</authors>
        <requireLicenseAcceptance>false</requireLicenseAcceptance>
        <description>.proto files NuGet package.</description>
        <dependencies>
          <dependency id="Google.Protobuf" version="3.14.0"/>
          <dependency id="Grpc" version="2.35.0"/>
        </dependencies>
        <contentFiles>
          <files include="any/any/Protos/**/*.proto" buildAction="None" copyToOutput="false" />
        </contentFiles>
    </metadata>
    <files>
        <file src="xxx.proto" target="contentFiles\any\any\Protos" exclude="google\**" />
        <file src="build\*.props" target="build" />
    </files>
</package>

4) 然后重新打包nuget项目的新版本。在安装新版本之前,请先清除 nuget 缓存,或者直接删除C:\Users\xxx\.nuget\packages下的所有文件。

在安装完nuget包后,请点击“Build”按钮执行目标操作。

更多类似于此问题

====================================================

功能二

您不能对nupkg本身进行任何内部步骤。您可以直接从外部主项目中复制该文件。

1)不要在您的 nuget 包中执行功能一下的任何步骤。使用旧的 nuget 包。

修改已安装了GRPCProtoFiles nuget 包的 A 项目的 csproj 文件。

PackageReference GRPCProtoFiles添加<GeneratePathProperty>true</GeneratePathProperty>,以生成一个独特的属性$(PkgGRPCProtoFiles)来获取nupkg内容的路径。

整体如下:

<ItemGroup>
    <PackageReference Include="GRPCProtoFiles" Version="1.0.0">
      <GeneratePathProperty>true</GeneratePathProperty>
    </PackageReference>
 </ItemGroup>

然后,在 Project A-->属性-->生成事件-->在预生成事件命令行下方添加以下内容:

xcopy  /s /e /y /i  $(PkgGRPCProtoFiles)\contentFiles\any\any\Protos  $(ProjectDir)\Protos

在此输入图片描述

或者,将此目标添加到ProjectA.csproj文件中:

<Target Name="CopyFiles" BeforeTargets="PrepareForBuild">
        <ItemGroup>
            <File Include="$(PkgGRPCProtoFiles)\contentFiles\**\*.*"></File>
        </ItemGroup>
        <Copy SourceFiles="@(File)" DestinationFolder="$(ProjectDir)\Protos"></Copy>
</Target>

enter image description here


1
好答案!真的很有帮助。愿上帝保佑你。 - Abraham Qian
2
我希望我可以多次点赞... :D 很棒的回答! - MBender
为了认可这个答案,点赞! - dadhi

0
我知道这已经过去了几年,但我在尝试做同样的工作时遇到了这个,我能够使用与上面第一个函数类似的语法添加我的proto文件。
实际上,我创建了3个不同的.nuspec文件和3个.props文件,一个用于客户端,一个用于服务器,一个用于两者。因此,根据使用情况,您可以使用PackageBlah-(client|server|both).X.X.X来使用,并获得正确的proto文件和您期望的生成代码。
首先,我的nuget包仅包含proto文件,因此您的目录结构可能略有不同。
我从一个nuspec文件开始,其中部分将我的proto文件放在一个名为protos的目录中,并将props文件放在构建文件夹中。
    <files>
        <file src="*.proto" target="\protos" />
        <!-- This line below will change if you're in the nuspec for client|server|both -->
        <file src="build-props\*-server.props" target="build" />
    </files>
.props文件的内容如下(这是整个文件):
<Project>    
    <ItemGroup>
        <Protobuf Include="$(MSBuildThisFileDirectory)..\protos\*.proto" GrpcServices="Both" ProtoRoot="$(MSBuildThisFileDirectory)..\protos">
            <Link>protos\%(Filename)%(Extension)</Link>
        </Protobuf>
    </ItemGroup>        
</Project>

请记住,GrpcServices 属性会根据您正在构建的包而有所不同。
对我来说,最终的结果是,我的项目包含了正确的 protobuf 引用,并且在构建过程中运行的 protoc 进程知道在哪里找到 proto 文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接