locked
Powershell tf.exe and DTE - different behavior from command line and function call RRS feed

  • Question

  • Hello,

    I am trying to create an automation process for generating source files and replacing existing ones in a visual studio project. However I have a problem when adding a file that in the past was deleted. the problem may be of how powershell executes tf.exe command or adding projectitems to dte OM.

    So what i do is something like that in pseudocode

    Function a

    {

     delete file 

    checkin 

    }

    Function b

    {

    copy new item to project folder

    add file to projectitems 

    checkin

    }

    when i call this funcitons from the command line one by one then it succeds and adds the file in the project. However when i call the second function inside funciton a or in the file itself then it copies the file to the locaiton adds it to source control but raises exception that the file already exists in source control

    Any thoughts??

    Kostas

    Monday, May 21, 2012 4:34 PM

Answers

  • Hi Kostas:

    The PowerShell script is running as multithreaded and it may be not waiting for the check-in to complete before trying to add the new file.  You can test this by running the script in the PowerShell ISE as it is single threaded.  If this is the case you will need to add logic in your script to confirm the tf delete before proceeding with the add.

    Let us know how it goes.


    Trevor Hancock (Microsoft)
    Please remember to "Mark As Answer" the replies that help.

    Tuesday, May 29, 2012 5:47 PM

All replies

  • Hard to say without knowing what delete file / checkin / add file to project items / checkin looks like code wise.  Psuedo-code generally isn't helpful when trying to debug problems over the internet.

    Ryan


    Monday, May 21, 2012 5:51 PM
  • Yes you are right...... :-)

    Although it 's not so clean, this also can be useful for someone else. I use it through powerconsole in visual studio. The problem occurs down in the lines after #add the files not in the project.

    set-alias tf "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\tf.exe" Function updateDomain() { # the Domain project folder $domainProj = "xxx.xxx.xxx" # the domain .cs files folder $domainFolder = "zzz" # the temporary folder where new/updated .cs files are generated $newFilesTempFolder = ".\temp" # the domain folder object from the development environment $dom = $DTE.Solution.Projects | Where-Object {$_.Name -eq $domainProj} | ForEach { $_.ProjectItems} | Where-Object {$_.Name -eq $domainFolder} # the full path filenames currently under domain folder $curFilesNames = $dom.ProjectItems | ForEach {$_.Properties} | ? {$_.Name -eq "LocalPath"} | % {$_.Value} # the files currently under domain folder $curFiles = gci $curFilesNames # the generated files in the temporary folder $newFiles = gci $newFilesTempFolder\*.cs # the not full path filenames currently under domain folder $curFilesNames2 = $curFiles | ? {!$_.PsIsContainer} | % {$_.Name} # compute the files that are in temporary but not in domain folder. Those should be added to project $tobeaddeditems = $newFiles | ? {!$_.PsIsContainer} | ? {$curFilesNames2 -notcontains $_.Name} # print them Write-Host "Items to be added to Project" Write-Host $tobeaddeditems | ForEach {$_.FullName} # the not full path file names of the temporary folder $Dir1 = $newFiles | ? {!$_.PsIsContainer} | % {$_.Name} # compute the items that are in the project but not in temporary folder $tobedeleteditems = $curFiles | ? {!$_.PsIsContainer} | ? {$Dir1 -notcontains $_.Name} # print them Write-Host "Items to be deleted from Project" Write-Host $tobedeleteditems | ForEach {$_.FullName} # the full path filenames of the files to be deleted $tobedeletedNames = $tobedeleteditems | ForEach {$_.FullName} # the not full path filenames of the files to be deleted $tobedeletedshortNames = $tobedeleteditems | ForEach {$_.Name} # the local path $localpath = $dom.Properties | ? {$_.Name -eq "LocalPath"} | % {$_.Value} # if there are file to be deleted if ($tobedeleteditems -ne $null) { Write-Host "Delete Items" # checkout to be deleted files Write-Host (tf delete $tobedeletedNames /noprompt /lock:checkout) Write-Host ($dom | ForEach { $_.ProjectItems} | ? {$tobedeletedshortNames -contains $_.Name} | ForEach { $_.Remove()} ) Write-Host $tobedeletedNames Write-Host (tf checkin "$localpath\.." /noprompt /recursive) # checkin the changes } # the full path filenames currently under domain folder $curFilesNames = $dom.ProjectItems | ForEach {$_.Properties} | ? {$_.Name -eq "LocalPath"} | % {$_.Value} # the files currently under domain folder $curFiles = gci $curFilesNames # checkout project current domain files Write-Host (tf checkout $curFilesNames /lock:checkout) # copy the new files in the domain folder if ($newFiles -ne $null) { Write-Host (Copy-Item $newFiles .\$domainProj\$domainFolder) } # add the files not in the project if ($tobeaddeditems -ne $null) { $dom = $DTE.Solution.Projects | Where-Object {$_.Name -eq $domainProj} | ForEach { $_.ProjectItems} | Where-Object {$_.Name -eq $domainFolder} Write-Host "Add Items" $tobeaddedNames = $tobeaddeditems | ForEach {$_.Name} $tobeaddedNewitems = gci .\$domainProj\$domainFolder\*.cs | ? {$tobeaddedNames -contains $_.Name} Write-Host ($tobeaddedNewitems | ForEach {tf add $_.FullName}) # add files to project $tobeaddedfullnames = $tobeaddedNewitems | ForEach { $_.FullName} Write-Host $tobeaddedfullnames Write-Host (tf checkin "$localpath\.." /noprompt /recursive) return $tobeaddedfullnames } # compute checkin items. tf checkin "$localpath\.."  /noprompt /recursive } Function addNewItems($items) { # the Domain project folder $domainProj = "xxx.xxx.xxx" # the domain .cs files folder $domainFolder = "zzz" $dom = $DTE.Solution.Projects | Where-Object {$_.Name -eq $domainProj} | ForEach { $_.ProjectItems} | Where-Object {$_.Name -eq $domainFolder} ForEach ($item in $items) { $dom.ProjectItems.AddfromFileCopy("$item") } } Function updateAndAdd() { $x = updateDomain addNewItems($x) } $x = updateDomain addNewItems($x)

    So if I call in the powershell command line, it works as expected

    $x = updateDomain addNewItems($x)

    But when I call the file directly calling the same functions, but from inside the file, it says that the file already exists. The same happend when I call updateAndAdd() which also calls the same two lines of code.

    Strange eh? I don't know if something clears up when one command finishes in the command line and then starts the other. Somthing that is not happening in the running loop of the interpreter.

    I think is the same as this

    http://social.msdn.microsoft.com/Forums/en/vsx/thread/f919fbc3-fbe0-4f1d-8ed8-6a0cee58fb22

    Thank you

    Kostas


    Kostas

    Monday, May 21, 2012 11:06 PM
  • Hi georguik,

    Thank you for your question.

    I am trying to involve someone familiar with this topic to further look at this issue. There might be some time delay. Appreciate your patience.

    Thank you for your understanding and support.


    Lucy Liu [MSFT]
    MSDN Community Support | Feedback to us

    Wednesday, May 23, 2012 6:34 AM
  • Hi Kostas:

    The PowerShell script is running as multithreaded and it may be not waiting for the check-in to complete before trying to add the new file.  You can test this by running the script in the PowerShell ISE as it is single threaded.  If this is the case you will need to add logic in your script to confirm the tf delete before proceeding with the add.

    Let us know how it goes.


    Trevor Hancock (Microsoft)
    Please remember to "Mark As Answer" the replies that help.

    Tuesday, May 29, 2012 5:47 PM