2012-05-31 20 views
10

Tôi đang viết gói dịch vụ cho dịch vụ Windows, ý tưởng là đồng nghiệp của tôi có thể tạo dịch vụ cửa sổ cài đặt gói và tất cả của các thiết lập đăng nhập mặc định, thư viện entlib và các nhiệm vụ giữ nhà khác sẽ được thiết lập cho chúng.Làm cách nào để có thể chèn các phần tử <DependentUpon> vào tệp csproj mục tiêu

Tôi đã nhận được khá nhiều thứ để làm việc, ngoại trừ một điều khiến tôi phát điên.

Trong thư mục nội dung của thư mục nuget của tôi, tôi có Service.cs và Service.Designer.cs chúng được thêm vào csproj đích nhưng chúng không liên quan.

Khi tôi nhìn vào các tập tin csproj tôi thấy:

<Compile Include="Service.cs"> 
    <SubType>Component</SubType> 
</Compile> 
<Compile Include="Service.Designer.cs" /> 

Nhưng tôi muốn xem:

<Compile Include="Service.cs"> 
    <SubType>Component</SubType> 
</Compile> 
<Compile Include="Service.Designer.cs"> 
    <DependentUpon>Service.cs</DependentUpon> 
</Compile> 

Bất kỳ ý tưởng, đẹp, chắc chắn nó sẽ liên quan đến kịch bản install.ps nhưng PowerShell tôi kỹ năng không tồn tại?

Là một bên, nuget có thể được sử dụng để xóa/ghi đè tệp? Cho đến nay nó dường như chỉ bỏ qua.

+0

Tôi hỏi như vậy sẽ trở thành một phần của câu hỏi của bạn. Tôi cũng khuyên bạn nên thử nghiệm điều này so với phiên bản mới nhất của NuGet, đó là [1.8] (http://nuget.codeplex.com/releases). – Sumo

Trả lời

12

Sau khoảng 2 ngày kể từ ngày powerhell và địa chỉ msbuild, tôi cuối cùng cũng có giải pháp làm việc. Xem bên dưới. Một lời cảnh báo gọi là project.Save() là rất quan trọng - nếu không có điều này bạn sẽ nhận được một cảnh báo "sửa đổi tập tin xung đột được phát hiện". Nếu bạn gọi project.Save() trước tiên, bạn sẽ chỉ được yêu cầu tải lại giải pháp khi bạn đã hoàn tất.

param($installPath, $toolsPath, $package, $project) 

#save the project file first - this commits the changes made by nuget before this  script runs. 
$project.Save() 

#Load the csproj file into an xml object 
$xml = [XML] (gc $project.FullName) 

#grab the namespace from the project element so your xpath works. 
$nsmgr = New-Object System.Xml.XmlNamespaceManager -ArgumentList $xml.NameTable 
$nsmgr.AddNamespace('a',$xml.Project.GetAttribute("xmlns")) 

#link the service designer to the service.cs 
$node = $xml.Project.SelectSingleNode("//a:Compile[@Include='Service.Designer.cs']", $nsmgr) 
$depUpon = $xml.CreateElement("DependentUpon", $xml.Project.GetAttribute("xmlns")) 
$depUpon.InnerXml = "Service.cs" 
$node.AppendChild($depUpon) 

#link the settings file to the settings.designer.cs 
$settings = $xml.Project.SelectSingleNode("//a:None[@Include='ServiceSettings.settings']", $nsmgr) 
$generator = $xml.CreateElement("Generator", $xml.Project.GetAttribute("xmlns")) 
$generator.InnerXml = "SettingsSingleFileGenerator" 
$settings.AppendChild($generator) 

$LastGenOutput = $xml.CreateElement("LastGenOutput", $xml.Project.GetAttribute("xmlns")) 
$LastGenOutput.InnerXml = "ServiceSettings.Designer.cs" 
$settings.AppendChild($LastGenOutput) 

#set the settings designer to be autogen 
$settingsDesigner = $xml.Project.SelectSingleNode("//a:Compile[@Include='ServiceSettings.Designer.cs']", $nsmgr) 
$autoGen = $xml.CreateElement("AutoGen", $xml.Project.GetAttribute("xmlns")) 
$autoGen.InnerXml = "True" 

$DesignTimeSharedInput = $xml.CreateElement("DesignTimeSharedInput", $xml.Project.GetAttribute("xmlns")) 
$DesignTimeSharedInput.InnerXml = "True" 

$AGDependentUpon = $xml.CreateElement("DependentUpon", $xml.Project.GetAttribute("xmlns")) 
$AGDependentUpon.InnerXml = "ServiceSettings.settings" 

$settingsDesigner.AppendChild($autoGen) 
$settingsDesigner.AppendChild($DesignTimeSharedInput) 
$settingsDesigner.AppendChild($AGDependentUpon) 

#fix up the project installer.  
$projectInstallerRes = $xml.Project.SelectSingleNode("//a:EmbeddedResource[@Include='ProjectInstaller.resx']", $nsmgr) 
$projectInstallerResDepUpon = $xml.CreateElement("DependentUpon", $xml.Project.GetAttribute("xmlns")) 
$projectInstallerResDepUpon.InnerXml = "ProjectInstaller.cs" 
$projectInstallerRes.AppendChild($projectInstallerResDepUpon) 

$projectInstallerDesigner = $xml.Project.SelectSingleNode("//a:Compile[@Include='ProjectInstaller.Designer.cs']", $nsmgr) 
$projectInstallerDesignerDepUpon = $xml.CreateElement("DependentUpon", $xml.Project.GetAttribute("xmlns")) 
$projectInstallerDesignerDepUpon.InnerXml = "ProjectInstaller.cs" 
$projectInstallerDesigner.AppendChild($projectInstallerDesignerDepUpon) 

#delete the bundled program.cs file. 
$prog = $xml.Project.SelectSingleNode("//a:Compile[@Include='Program.cs']", $nsmgr) 
$prog.SelectSingleNode("..").RemoveChild($prog) 

#delete the bundled service1 file 
$oldServiceFile = $xml.Project.SelectSingleNode("//a:Compile[@Include='Service1.cs']", $nsmgr) 
$oldServiceFile.SelectSingleNode("..").RemoveChild($oldServiceFile) 

$oldServiceDesignerFile = $xml.Project.SelectSingleNode("//a:Compile[@Include='Service1.Designer.cs']", $nsmgr) 
$oldServiceDesignerFile.SelectSingleNode("..").RemoveChild($oldServiceDesignerFile) 

#save the changes. 
$xml.Save($project.FullName) 

Shameless tự cắm: I'll do a full write up of the solution and issues I encountered on my blog cianm.com Hy vọng điều này giúp tiết kiệm một ai đó ngoài kia một thời gian.

2

Dưới đây là một ví dụ ngắn sử dụng Build.Evaluation là một phần của Visual Studio 2010+

$buildProject = @([Microsoft.Build.Evaluation.ProjectCollection]::GlobalProjectCollection.GetLoadedProjects($project.FullName))[0] 


$toEdit = $buildProject.Xml.Items | where-object { $_.Include -eq "Service.Designer.cs" } 
$toEdit.AddMetaData("DependentUpon", "Service.cs") 
# ... for the other files 

$project.Save() 
5

Tôi nghĩ một cách dễ dàng hơn để làm điều này (và có thể hỗ trợ nhiều hơn nữa) là thông qua việc biến $project trỏ đến Dự án DTE.

Lưu ý: Tôi sẽ tham dự vào một năm sau, nhưng phải đối mặt với một vấn đề tương tự. Tôi đã tìm thấy câu trả lời này và bắt đầu sử dụng nó, nhưng tôi gặp sự cố với lệnh Lưu ở cuối tập lệnh PowerShell - nếu tôi có một gói cài đặt phụ thuộc vào gói có kịch bản PowerShell, lệnh Lưu "đã phá vỡ mọi thứ" các gói khác không thể cài đặt đúng cách. Dù sao, bây giờ tôi đang sử dụng NuGet 2.5, nhưng DTE đã không thay đổi với bất kỳ ý nghĩa kể từ VS 2003 vì vậy điều này sẽ làm việc ngay cả trong NuGet cũ bạn đang sử dụng.

param($installPath, $toolsPath, $package, $project) 

# Selections of items in the project are done with Where-Object rather than 
# direct access into the ProjectItems collection because if the object is 
# moved or doesn't exist then Where-Object will give us a null response rather 
# than the error that DTE will give us. 

# The Service.cs will show with a sub-item if it's already got the designer 
# file set. In the package upgrade scenario, you don't want to re-set all 
# this, so skip it if it's set. 
$service = $project.ProjectItems | Where-Object { $_.Properties.Item("Filename").Value -eq "Service.cs" -and $_.ProjectItems.Count -eq 0 } 

if($service -eq $null) 
{ 
    # Upgrade scenario - user has moved/removed the Service.cs 
    # or it already has the sub-items set. 
    return 
} 

$designer = $project.ProjectItems | Where-Object { $_.Properties.Item("Filename").Value -eq "Service.Designer.cs" } 

if($designer -eq $null) 
{ 
    # Upgrade scenario - user has moved/removed the Service.Desginer.cs. 
    return 
} 

# Here's where you set the designer to be a dependent file of 
# the primary code file. 
$service.ProjectItems.AddFromFile($designer.Properties.Item("FullPath").Value) 

Hy vọng rằng sẽ giúp mọi người trong tương lai tìm cách đạt được điều gì đó tương tự. Làm theo cách này, bạn tránh được vấn đề với cài đặt gói phụ thuộc không thành công vì dự án đang được lưu ở giữa gói cài đặt.

Các vấn đề liên quan