如何从版本控制中省略CMS,同时自动包含/恢复到项目?

时间:2014-01-28 22:33:10

标签: asp.net version-control msbuild content-management-system kentico

我认为这个问题一般适用于CMS。

我正在使用CMS,Kentico,用于特定的Web应用程序。 CMS安装程序生成自己的样板项目,包含10,000多个文件,该项目相当于一个可运行的Web应用程序。很少有CMS提供的文件可供修改。然而,标准做法是将自定义代码添加到项目中,并将整个项目检查为源代码控制。

我不喜欢检查整个CMS的想法。我更喜欢我的存储库只包含项目特有的代码,而供应商文件则自动从其他地方“拉入”。例如,Visual Studio可以将NuGet包恢复到项目中的固定位置,版本控制可以忽略此位置。

在某种程度上,使用CMS进行开发比使用典型供应商库时更脏。通常,您自己的代码依赖于库,而库独立于您的代码。但是,CMS希望 您的应用程序,并且您自己的代码交织在一起。 CMS需要自定义其自己提供的文件。您不能只是将CMS文件“拉入”固定位置,然后忽略该位置。

鉴于这种情况,我仍然希望尽可能多地省略CMS文件。到目前为止,我已经确定了这个策略:

  1. 在标准的本地路径上保留CMS提供的文件的原始,只读副本。
  2. 创建一个新的项目根目录。
  3. 将CMS提供的项目文件复制到项目根目录。
  4. 在复制的项目文件中,将10,000+文件路径更改为指向项目根目录外部的原始CMS文件。
  5. 仅将包含自定义代码的文件放入项目根目录。如果必须修改CMS提供的文件,请将其复制到项目根目录并使用该副本。
  6. 这种策略在理论上听起来不错,但在实践中却更为复杂。以下是一些并发症:

    • 将10,000多个文件路径更改为外部文件中的“链接”,结果不仅仅是查找替换操作。需要更复杂的映射来保留原始项目的目录结构。

    • Web服务器要求所有文件位于同一目录中。使用项目文件链接到外部文件可以进行编译,但是您已将Web根分成两部分。

    对于后一个问题,似乎最好的解决方法是执行构建后复制操作。这本身比起初看起来更复杂。

    在我写这篇文章时,我开始觉得我应该继续将整个工作CMS转储到我的存储库中。感觉很脏,但这简直太难了。在我这样做之前,有没有人对我如何实现目标有任何经验或想法?

    重述我的问题:如何从我的版本控制存储库中排除CMS提供的文件,同时仍然将它们包含在我的项目/构建脚本和我的Web应用程序根目录中?

3 个答案:

答案 0 :(得分:1)

以下是如何实现这一目标的另一个想法:

  • 我为Kentico DLL和Kentico安装程序建立了一个标准的本地目录,它不受版本控制。
  • 我创建了KenticoSupport.csproj,这是一个扩展内置Kentico类型的类库,就像它们要扩展一样。这还将包含内容,例如JS,CSS,ASPX,ASCX等文件。这将是版本控制,但它引用了中央Kentico DLL,它们不受版本控制。
  • 我创建了KenticoBuilder.csproj,这是一个主要是空项目,主要是构建脚本。它还包含一些简单的* .patch文件来修改匹配的Kentico文件,例如Web.config和Global.asax.cs。这是受版本控制的。

以下是KenticoBuilder.csproj脚本的作用:

  • 构建KenticoSupport.csproj。
  • 创建一个输出目录,该目录将同时用作Web根目录和项目目录。
  • 将原始Kentico项目文件安装/复制到输出目录中。
  • 将补丁应用于匹配输出目录中的Kentico文件(主要是添加配置行和自定义引导)。
  • 将自定义DLL和内容从KenticoSupport复制到输出目录中的匹配位置。
  • 在输出目录中构建项目。

这很复杂,但我认为它可能会起作用。思绪,有人吗?

答案 1 :(得分:0)

Kentico应该很快就会解决这个问题,你可以参考预先构建的dll而不是每次修改C#时重建整个CMS。

在此之前,您是否考虑使用Symbolic Links来引用原始文件?然后在需要时用你的修改过的文件覆盖链接?

如果您之前没有使用过,请参阅this other question。 mklink附带了更新的Windows版本(命令行),但也有一堆基于第三方GUI的应用程序。

答案 2 :(得分:0)

我提出了一个理想的策略:

  • 将原始CMS文件放在外部“代码库”位置,并将其设置为只读以便进行测量。
  • 制作CMS提供的项目文件的副本。
  • 转换所有项目项以链接到代码库的副本,包括程序集引用。 MSBuild所需的link元素使这一点复杂化,因此我编写了一个小的控制台应用程序来解析XML并生成必要的元素。我还在属性中存储库的路径。

此时,您有一个可编辑的项目。这些文件都只是指向只读,基线,CMS提供的文件的链接,但IDE显示了一个很好的目录结构,就好像文件实际上在您的存储库中一样。在自定义时,您可以使用自己的实际文件替换链接。

但是,您的网站文件现在分为两个完全不同的位置。 Web服务器需要它们实际位于同一目录中。这是一些脚本派上用场的地方。

  • 使用构建脚本工具,插入构建后事件,将链接文件复制到项目目录中。当然,您可以省略已编译的文件。这是我用MSBuild做的方式(感谢这个blog post):

    <Target Name="AfterBuild">
    
        <ItemGroup>
            <LinkedKenticoFiles Include="@(None);@(EmbeddedResource);@(Content)"
                Condition="$([System.String]::new('%(FullPath)').StartsWith('$(MY_LIBRARY_BASE_PATH)'))" />
        </ItemGroup>
    
        <Copy SourceFiles="%(LinkedKenticoFiles.Identity)"
            DestinationFiles="%(LinkedKenticoFiles.Link)"
            SkipUnchangedFiles='true' />
    
    </Target>
    
  • (可选)插入清除事件以删除这些文件。我使用类似的MSBuild语法删除文件,因为它留下了空目录,我也删除了空目录。 (感谢this answer。)

    <Target Name="BeforeClean">
    
        <ItemGroup>
            <LinkedKenticoFiles Include="@(None);@(EmbeddedResource);@(Content)"
                Condition="$([System.String]::new('%(FullPath)').StartsWith('$(MY_LIBRARY_BASE_PATH)'))" />
        </ItemGroup>
    
        <Delete Files="%(LinkedKenticoFiles.Link)" />
    
        <ItemGroup>
            <Directories Include="$([System.IO.Directory]::GetDirectories($(MSBuildProjectDirectory), '*', System.IO.SearchOption.AllDirectories))" />
            <Directories>
                <Files>$([System.IO.Directory]::GetFiles("%(Directories.Identity)", "*", System.IO.SearchOption.AllDirectories).get_Length())</Files>
            </Directories>
        </ItemGroup>
        <RemoveDir Directories="@(Directories)" Condition="%(Files)=='0'" />
    
    </Target>
    
  • (可选)使源控件忽略站点/项目文件夹,以避免签入临时复制的站点文件。