Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nuget.exe breaking relative path #7657

Closed
PNI-GS opened this issue Dec 21, 2018 · 27 comments
Closed

Nuget.exe breaking relative path #7657

PNI-GS opened this issue Dec 21, 2018 · 27 comments
Assignees
Labels
Functionality:Restore Priority:1 High priority issues that must be resolved in the current sprint. RegressionFromPreviousRTM A regression from the last RTM. Example: worked in 6.2, doesn't work in 6.3 Style:Packages.Config Type:Bug
Milestone

Comments

@PNI-GS
Copy link

PNI-GS commented Dec 21, 2018

Details about Problem

NuGet product used (NuGet.exe | VS UI | Package Manager Console | dotnet.exe): NuGet.exe

NuGet version (x.x.x.xxx): 4.8.x+

dotnet.exe --version (if appropriate):

VS version (if appropriate): VS2017

OS version (i.e. win10 v1607 (14393.321)): Windows 2008R2 & Azure DevOps

Worked before? If so, with which NuGet version: 4.7.x

Detailed repro steps so we can see the same problem

  1. Unknown how to fully reproduce, Relative path has been unable to restore from path (Log info below) as something has changed to resolve hint path

...

Other suggested things

Verbose Logs

TeamCity:
E:\work\4e6219bf893eb490.nuget\nuget.targets(87,9): error : Could not find a part of the path 'E:\work\4e6219bf893eb490\ \packages\RabbitMQ.Client.3.6.2'.

Azure DevOps:
##[error].nuget\nuget.targets(87,9): Error : Could not find a part of the path 'D:\a\1\s\ \packages\RabbitMQ.Client.3.6.2'.

Sample Project

Very helpful if you can zip a project and paste into this issue!

Unfortunately I do not have a sample project I can provide at this time.

@rrelyea
Copy link
Contributor

rrelyea commented Dec 21, 2018

Can u describe the relative path part of this repro?
Which paths are relative? where?

@PNI-GS
Copy link
Author

PNI-GS commented Dec 21, 2018

Here is the line from my csproj:

<Reference Include="RabbitMQ.Client, Version=3.6.2.0, Culture=neutral, PublicKeyToken=89e7d7c5feba84ce, processorArchitecture=MSIL">
  <HintPath>..\packages\RabbitMQ.Client.3.6.2\lib\net45\RabbitMQ.Client.dll</HintPath>
</Reference>

Seems that 2 of my 5 projects in one solution seems to be having this problem. I thought it was at our code level but I don't see any code changes that would impact this as well as just swapping to an older nuget.exe resolves the issue.

@rrelyea
Copy link
Contributor

rrelyea commented Dec 21, 2018

Reading a few of these may be helpful?
https://github.com/nuget/home/issues?q=is%3Aissue+hintpath+relative+is%3Aclosed
relative hintpaths are a fragile design.

@PNI-GS
Copy link
Author

PNI-GS commented Dec 21, 2018

Thank you.

I will do some reading but still something must be broken within the system that has now caused an instability and broken backwards compatibility.

@bscheutjens
Copy link

I have the same issue. Please take a look at the original post and the part:

E:\work\4e6219bf893eb490\ \packages\RabbitMQ.Client.3.6.2

There is a space between "4e6219bf893eb490" and "\packages\RabbitMQ.Client.3.6.2". In my case that space should be a folder name where my solution is located.

When I replace the nuget.exe in the folder ".nuget" by the previous version (4.7.1) everything works fine, so this must be a bug introduced in version 4.9.2.

@rrelyea rrelyea added this to the 4.9.3 milestone Dec 21, 2018
@rrelyea rrelyea added Type:Bug RegressionFromPreviousRTM A regression from the last RTM. Example: worked in 6.2, doesn't work in 6.3 Functionality:Restore Style:Packages.Config Priority:1 High priority issues that must be resolved in the current sprint. labels Dec 21, 2018
@zivkan
Copy link
Member

zivkan commented Dec 21, 2018

@PNI-GS @bscheutjens I'm unable to reproduce the error.

From the information provided, I can see that your project uses packages.config, not PackageReference, where the project is in a subdirectory from the sln file, so you're not using a src\Project folder structure. I don't have any other ideas at the moment.

I created a sample repo, using the RabbitMQ tutorials. I created one project with no spaces in the path, and another one with spaces in the path. But my build was completed successfully.

If you can't provide us with a sample reproduction, can you look at my sample and tell me what differences there are between my attempt and your repo?

For example, I didn't include a nuget.config. Do you use a nuget.config? If so, which settings do you set?

Can you reproduce on your local machine by downloading nuget.exe and running nuget.exe restore from the command line? I tried 4.8.1, 4.9.1 and 4.9.2, but none of them fail in the way your issue describes.

@jainaashish
Copy link
Contributor

jainaashish commented Dec 21, 2018

@PNI-GS @bscheutjens are you guys running nuget.exe restore command with solution or project file? or any other command... because with packages.config restore command has nothing to do with reference items in csproj.

Also, what is this path E:\work\4e6219bf893eb490.nuget? like solution directory, or root directory? where is the nuget.exe downloaded? what are the other assemblies or files adjacent to nuget.exe? it will be useful if you can give an idea about your folder structure about these things.

@zivkan
Copy link
Member

zivkan commented Dec 21, 2018

The .nuget/nuget.targets in the error message gave me an idea. Old versions of Visual Studio (2010 and maybe 2012/2013, but I'm not sure) didn't have good intergration with NuGet, and you would right click your solution and select "enable NuGet restore". I think that functionality used to create a .nuget directory with nuget.exe, and maybe nuget.targets. Therefore, my assumption is that this project/solution was originally from these old version of Visual Studio.

If I'm correct, my recommendation is to delete the nuget.exe and nuget.targets files from your repo. If there's also a nuget.config file in your .nuget/ directory, check to see if there are any settings you still use and if not, just delete the whole .nuget folder. Any .csproj files that <Import Project="..\.nuget\nuget.targets" /> will need to have that line deleted, in order to undo the VS2010-era nuget integration.

I'm creating a VM to download/install these old versions of VS onto, to test my theory, but it's slow to do all this. If you read this comment before I finish testing, you can test it more quickly than me. If this is the root-cause, then downloading new nuget.exe from nuget.org and doing nuget.exe restore should reproduce the error, so it's easy/quick to test.

@bscheutjens
Copy link

I'm using VS2013 Professional. We use SVN for version control and we auto ignore executables, so the nuget.exe is never added to SVN. So when somebody checks something out we always have to use the option "Enable NuGet Package Restore" on the solution from within VS (I'm not sure which command is executed), which creates the .nuget subfolder (if that was also not added to SVN) and and three files within. It appears the nuget.exe is downloaded and is always the latest version. Since yesterday this downloads version 4.9.2 and the solutions don't build anymore. When I replace nuget.exe with version 4.7.1, which I copied from another solution, the issue is solved and I'm able to build the solution again.

Because, when you know this, it is very simple to reproduce I've attached the most simple project I could create which already has the issue. Please note I just created this solution, it has not been on SVN. I really didn't so anything special. I just created the solution, installed a random package and clicked "Enable NuGet Package Restore". After these steps I was unable to compile the solution. I get the following three errors (sorry that they are in Dutch):

"Kan een gedeelte van het pad D:\Development\Software\TestNuget\ \packages\Google.Protobuf.3.5.1 niet vinden."

"Kan een gedeelte van het pad D:\Development\Software\TestNuget\ \packages\MySql.Data.8.0.13 niet vinden."

"The command ""D:\Development\Software\TestNuget.nuget\NuGet.exe" install "D:\Development\Software\TestNuget\TestNuget\packages.config" -source "" -NonInteractive -RequireConsent -solutionDir "D:\Development\Software\TestNuget\ "" exited with code 1."

The first two error messages are similar to the one from the first post, stating that a part of the folder can't be found. As you can see there is also a space. The correct path (which doesn't have any space in it) is shown in the last error message.

nugeterrors

TestNuget.zip

@zivkan
Copy link
Member

zivkan commented Dec 27, 2018

Thanks for the sample, it was useful. I managed to get VS2013 installed on a VM today and test myself, and find the root cause. Unfortunately it doesn't have an obvious, simple solution

Root cause

Change to NuGet.exe

In NuGet 4.8 we added long path support, which involves setting the Switch.System.IO.UseLegacyPathHandling AppContext switch to false. This changes mscorlib's behaviour from previously normalising out directories whose name is a space to no longer doing so. For example, when the flag is true, which is the default for exe's targeting .NET Framework 4.6 path\ \path2 gets normalised to path\path2. But the directory whose name is a space is left in when the flag is explicitly set to false, or when the .exe targets .NET Framework 4.6.2 or above. This causes an error when trying to create a file or directory under that path.

Why NuGet.exe is being called with a space in the SolutionDir path

The reason that NuGet.exe is looking at a directory whose name is a space because in VS2013 when you tell it to enable package restore on the solution, it adds a NuGet V2-era NuGet.targets file to the solution, and makes your csproj import it. It builds up a argument list to which it will use pass to nuget.exe, including the solution directory which it adds a space to.

The path is being surrounded by double quotes to support spaces in the path. The reason a space is added to the end is easiest to show using examples of arguments on the command line, and what is available in Program.Main's argument list

command line Program Main args
"c:\path\ " c:\path\ (there's a space on the end)
"c:\path\" c:\path\" (" is an invalid character in a path and throws exceptions if used in System.IO classes)
"c:\path\\" c:\path\ (this is our ideal case)
"c:\\path\\" c:\\path\ (doesn't seem to cause a problem currently, but neither did the " " directory until now)

So, my guess as to why the space was being added to the end of the directory was to avoid the second case in the table above where the double quotes character got added to the path.

Workarounds

Affected customers can do either of two things to avoid this issue:

  1. Replace nuget.exe with v4.7.1 or older.

When "Enable package restore" is selected in Visual Studio 2012 or 2013's solution right click menu, it creates a directory named .nuget and adds 3 files, nuget.config, nuget.targets and nuget.exe. The customer can download a version of nuget.exe prior to 4.8 and replace the version that Visual Studio wrote. Since these older versions of nuget.exe do not support long path names, it avoids the changed file normalisation behaviour of the .NET runtime.

  1. Don't use "enable package restore".

This functionality was removed from Visual Studio 2015 and later, so customers can prepare for future upgrades by no longer using it before upgrading. Visual Studio 2013 will still restore packages on build, so it will not affect development work. If the customer has a CI build, they will need the build script call nuget.exe restore, rather than having msbuild call it. They will need to check in their own copy of nuget.exe into source control, or download it as part of the build. If nuget.exe restore my.sln is used, the -solutiondir path does not need to be specified. If a different nuget restore target is used where -solutiondir or -packagesdir must be passed, the build script can pass the correct path avoiding the spaces and quotes issues we have in our v2 targets file.

If a customer has a solution where package restore has already been enabled, the steps to undo the changes are not difficult, but there is no simple UI to do it automatically. It involves deleting the .nuget folder and removing about 8 lines of XML from every affected csproj and vsproj. An easy way to see what needs to be removed is to create a new test solution, with a project that uses NuGet packages, commit it to source control (git is great for this, because it doesn't need a server, it can be done entirely locally), then enable package restore on the solution, commit again, and look at the commit diff.

Fix

Reverting support for long paths is not an option.

One option is to trim trailing spaces from the solution path in NuGet.exe. There are some issues with this option. First, NTFS (and I expect other file systems) technically support directories whose name is just a single space. As unlikely as it is that anyone would want to use this, it's technically valid. This issue appearing only now that we enabled long path support is a good example of why we shouldn't make assumptions about characters in a path, so I fear trimming spaces may lead to new bugs in the future. The .NET team are removing path validation from the .NET runtime and just using the operating system's error codes when accessing files/directories, because of false positives and false negatives from their existing validation logic, particularly since different file systems on different operating systems have different rules. If the .NET runtime is removing validation/normalisation, we should learn from them and avoid adding any. Secondly, nuget.exe was only doing what it was told. Removing unwanted characters should be done at the source, not later in the workflow when we've lost context about whether it was intentional or not.

Another option is to investigate changing NuGet.targets so that it no longer calls nuget.exe with a path containing a trailing space. Given that the NuGet team is no longer servicing VS2013, we cannot modify the NuGet extension. However, since enabling package restore on the solution automatically downloads the latest NuGet client (probably from the NuGet.CommandLine package), there's a chance that the NuGet.targets file is also downloaded (probably from the NuGet.Build package), so we might be able to simply push a new update of this package. This should be investigated.

@zivkan
Copy link
Member

zivkan commented Jan 2, 2019

In addition to the workarounds I proposed in the comment above, I want to add a 3rd option:

Edit .nuget\nuget.targets and replace the line:

<PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT'">"$(SolutionDir) "</PaddedSolutionDir>

with

<PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT'">"$([MSBuild]::EnsureTrailingSlash('$(SolutionDir)'))\"</PaddedSolutionDir>

This is also my proposed fix for the issue, but we need to wait until next week for the people needed to approve fixes to old versions of VS to come back to work.

However, my suggestion is still to avoid using "Enable NuGet Package Restore". It's simply not needed, even with VS2013 and no longer exists after that version.

@bscheutjens
Copy link

Thanks for the explanation. I just came back to the office from my holiday and I will check everything out and come back with a full reply.

I do have one remark though. I totally understand you guys stopped supporting older version. However, in this case I really would like you to make an exception, if possible. In the situation as-is an issue is automatically pushed to certain users and that should be avoided, even if their version is no longer supported.

@bscheutjens
Copy link

As promised my full reply.

First of all thanks for the detailed explanation. It makes things clear to me and I understand the reasons behind the proposed workarounds and the reason why this can't just be fixed. But more on these later on.

Workaround 1 - Use older version
This works, but should only be a temporary workaround.

Workaround 2 - Don't use Package Restore
I've tested to undo the package restore on a live solution and that worked. The only "danger" is that the option "Enable NuGet Package Restore" is back and it is very easy to accidentally click on it.

Workaround 3 - Replace a line in nuget.targets
When I try this, the projects aren't loaded anymore. I get the following error:

Invalid static method invocation syntax: "[MSBuild]::EnsureTrailingSlash('$(SolutionDir)')". Method '[MSBuild]::EnsureTrailingSlash' not found. Static method invocation should be of the form: $([FullTypeName]::Method()), e.g. $([System.IO.Path]::Combine(a, b)).

Fix
I understand why you don't want to revert the change to support long paths. However, like mentioned in my previous answer, I really hope you make an exception regarding changes to unsupported versions. Although there are possible workarounds, the situation as-is pushes an issue to users. If this can be solved by making a change so those users don't have to change there way of working, that should always be preferred. I'm very aware about the fact we use older versions, but we shouldn't be impacted outside of our control. If you guys introduce changes which aren't available/compatible with the version we use that is ok, as long as we have the opportunity to keep working as we have been used to for all these years without having to manually apply a workaround. For me it doesn't matter if that is done by not pushing the latest version or by changing the code regarding the older version.

@tombogle
Copy link

tombogle commented Jan 9, 2019

I have a project that also affected by this problem, but I use VS 2015. My csproj file has these two lines:

    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
    <RestorePackages>true</RestorePackages>

Workaround #1 is probably not a viable option, certainly not long term. Workaround #2 does not seem to be relevant, unless it is somehow related to the above entries. I see two checkboxes in the UI under "Package Restore" ("Allow NuGet to download missing packages" and "Automatically check for missing packages during build in Visual Studio"). Although these are not project-specific, I'm vaguely guessing that they might be related to that setting. I haven't tried changing those settings or manually setting RestorePackages to false, but if this is required, then this is not merely a VS2013 problem. Workaround #3 also does not seem to be relevant, since there is no PaddedSolutionDir entry in my NuGet.targets file. My local build is working fine. This problem is only happening on the CI build on TeamCity. The line that seems to set SolutionDir in NuGet.targets is:

    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)\..\</SolutionDir>

It doesn't seem likely that that line could be responsible for adding a trailing space.

@tombogle
Copy link

tombogle commented Jan 9, 2019

It appears that the solution is to change the PackageOutputDir from
<PackageOutputDir Condition="$(PackageOutputDir) == ''">$(TargetDir.Trim('\\'))</PackageOutputDir>
to:
<PackageOutputDir Condition="$(PackageOutputDir) == ''">$(TargetDir).Trim('\\', '/')</PackageOutputDir>
I don't know why some of our projects had the former, but fortunately, we had some that had the correct version, and that seems to fix the problem.

@rrelyea rrelyea modified the milestones: 4.9.3, 4.9.x Jan 9, 2019
@tombogle
Copy link

tombogle commented Jan 9, 2019

Turns out my proposed fix was a red herring. It is consistently building correctly on one of the build agents and failing on the other. Not sure what the difference is between the two, so now I'm not sure if/how it's related the problem in this thread.

@zivkan
Copy link
Member

zivkan commented Jan 10, 2019

@bscheutjens thanks for testing the workarounds and reporting the error with my 3rd workaround. I installed VS2017 on my VS2013 VM to test something, and I forgot I was using MSBuild 15. I'll make sure I test older msbuild versions for a better fix.

@tombogle I did another test of using "Enable NuGet Package Restore" in VS2013, and it added the following lines to my csproj. In the first <PropertyGroup> it added

    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
    <RestorePackages>true</RestorePackages>

and near the end of the file, as a child of the root <Project> element it added

  <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
    <PropertyGroup>
      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
    </PropertyGroup>
    <Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
  </Target>

This is in addition to creating a .nuget folder in the solution folder, adding nuget.config, nuget.targets and nuget.exe to it, and adding all those files to the solution as solution items.

Since you see some of the above in your project that you use with VS2015, my best guess is that it was originally created, or at least used, in VS2010, VS2012 or VS2013, and someone had used "Enable NuGet Package Restore" on the solution. Newer versions of Visual Studio will not delete these changes, but after installing VS2015 onto my VM, creating new projects and trying things within the IDE, I can't find a way for any of these things to be added. New project templates don't contain it.

@bscheutjens
Copy link

@bscheutjens thanks for testing the workarounds and reporting the error with my 3rd workaround. I installed VS2017 on my VS2013 VM to test something, and I forgot I was using MSBuild 15. I'll make sure I test older msbuild versions for a better fix.

@zivkan You're welcome and no problem. I'm happy to test any new possible fix.

@tombogle
Copy link

The line
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
seems to be the key determining factor in what happens. I've figured out that the difference between the two build agents is that one already had the older version of buget.exe and did not try to update it, so it works. The other build agent apparently did not have nuget.exe, so when it downloaded the latest version, it showed the failing condition. I can now reproduce this on my local build machine by deleting the cached version of nuget.exe so that the newer version is downloaded.
With the new version of nuget.exe:

  • If I remove the offending line from the csproj file, the build succeeds in VS2015 but FAILS if I build using msbuild to build my proj file
  • If I keep the offending line in the csproj file, the build fails in VS2015 (i.e., it has the '/ /' in the path) but succeeds if I build using msbuild to build my proj file.

tombogle added a commit to sillsdev/hearthis that referenced this issue Jan 10, 2019
… SolutionDir

This allows it to work with the latest version of NuGet.
Since some packages that HearThis needs require a more recent version of NuGet, I also added a conditional command to update nuget to the latest version if it already exists.
(See NuGet/Home#7657 for background)
@tombogle
Copy link

tombogle commented Jan 10, 2019

Well, I've solved my problems and I feel about 80% confident that what I did was at least mostly correct. Here's what I did:

  • I was able to remove the SolutionDir and RestorePackages elements and the "EnsureNuGetPackageBuildImports" target from the csproj files. (They were unnecessary but did not contribute to the problem.)

  • I could not remove the import of NuGet.targets because we had to customize that file to add another PackageSource in order to get a package used in our CI process.

  • In NuGet.targets I changed the trailing space for the -solutionDir switch to a forward slash on the line that defines the RestoreCommand:
    ... -solutionDir "$(SolutionDir)/" ...

  • I changed the _DownloadNuGet target to ensure that nuget.exe is updated as follows:
    <Target Name="_DownloadNuGet" Condition=" '$(DownloadNuGetExe)' == 'true'"> <Exec Command="$(NuGetExePath) update -self" Condition="Exists('$(NuGetExePath)')" /> <DownloadNuGet OutputFilename="$(NuGetExePath)" Condition="'$(OS)' == 'Windows_NT' AND !Exists('$(NuGetExePath)')" /> <Exec Command="wget https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" WorkingDirectory="$(NuGetToolsPath)" Condition="'$(OS)' != 'Windows_NT' AND !Exists('$(NuGetExePath)')" /> </Target>

I'm especially uncertain about that last part, as it seems like it ought to be the default behavior. I'm almost sure that when building in VS2015, it it using some other version of NuGet.exe because some of our packages claim to require a newer version that what I see in the .nuget folder. But since I found a plethora of very outdated versions in the .nuget folders of several different products, and since it appeared as though that was the difference on our build agents, I decided it was best to force this. (Interestingly, when I ran the build on the agent that I suspected of having the outdated version, the output seemed to suggest otherwise. Both agents seemed to claim to have the current version already.)

In cleaning up various other projects, I discovered that one had already replaced the trialing space with a period. It appears that that solution works regardless of what version of NuGet is used. So if anyone needs to use NuGet.targets and wants it to work with older and newer versions of NuGet, that's probably a good approach.

@zivkan
Copy link
Member

zivkan commented Jan 11, 2019

An update to my workaround 3, it should be possible to replace the PaddedSolutionDir definition for the Windows_NT OS with the following two lines:

<PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT' and HasTrailingSlash('$(SolutionDir)')">"$(SolutionDir)\"</PaddedSolutionDir>
<PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT' and !HasTrailingSlash('$(SolutionDir)')">"$(SolutionDir)"</PaddedSolutionDir>

I tested with VS2013 and VS2010. I didn't test with VS2012, but if it works with both the newer and older version, I feel confident.

Another option is similar to what tombogle wrote earlier:

<PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT' ">"$(SolutionDir.TrimEnd('\\')"</PaddedSolutionDir>

Although I haven't tested it.

@bscheutjens
Copy link

An update to my workaround 3, it should be possible to replace the PaddedSolutionDir definition for the Windows_NT OS with the following two lines:

<PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT' and HasTrailingSlash('$(SolutionDir)')">"$(SolutionDir)\"</PaddedSolutionDir>
<PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT' and !HasTrailingSlash('$(SolutionDir)')">"$(SolutionDir)"</PaddedSolutionDir>

I tested with VS2013 and VS2010. I didn't test with VS2012, but if it works with both the newer and older version, I feel confident.

I tested this with VS2013 in combination with the current version of NuGet.exe (4.9.2) and the previous version (4.7.1). Both work.

Another option is similar to what tombogle wrote earlier:

<PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT' ">"$(SolutionDir.TrimEnd('\\')"</PaddedSolutionDir>

Although I haven't tested it.

I can't get this one to work. I replaced the existing two lines with this single line and what happens is that it creates extra subfolders in each project folder and puts the packages in each of those.

nuget

In case of this test solution it does build, but when I try this on a live solution with multiple projects the packages are downloaded to these subfolders in each project, but the build fails with errors. All of these errors are on our internal NuGet packages (we use an internal package source for our commonly used libraries and components) and only the packages which have been released as a prerelease. Also all errors are on source files. I can't really post a screenshot because I would have to mask some parts and the masked image isn't really clear.

@zivkan
Copy link
Member

zivkan commented Mar 5, 2019

Hello anyone still looking at this issue. I published a new NuGet.Build package, which is where Visual Studio gets the NuGet.targets file which is added to the solution. Therefore, anyone using the "solution right click -> Enable NuGet Package Restore" should no longer have build errors. Anyone who did this before the 20th of December should also be unaffected, since it was before we published the NuGet.CommandLine package that no longer used legal path normalization.

Any customer affected, those who enabled the feature between the 20th of December and today, should manually edit their NuGet.targets file in the same way that the PR modified the file: https://github.com/NuGet/NuGet2/pull/125/files#diff-ded6a780d99e2610a3eebaafa90a4622

Change

        <PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT'">"$(SolutionDir) "</PaddedSolutionDir>
        <PaddedSolutionDir Condition=" '$(OS)' != 'Windows_NT' ">"$(SolutionDir)"</PaddedSolutionDir>

to

        <PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT' and HasTrailingSlash('$(SolutionDir)')">"$(SolutionDir)\"</PaddedSolutionDir>
        <PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT' and !HasTrailingSlash('$(SolutionDir)')">"$(SolutionDir)"</PaddedSolutionDir>
        <PaddedSolutionDir Condition=" '$(OS)' != 'Windows_NT' ">"$(SolutionDir)"</PaddedSolutionDir>

@brwertz80
Copy link

brwertz80 commented Aug 3, 2020

        <PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT' and HasTrailingSlash('$(SolutionDir)')">"$(SolutionDir)\"</PaddedSolutionDir>
        <PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT' and !HasTrailingSlash('$(SolutionDir)')">"$(SolutionDir)"</PaddedSolutionDir>
        <PaddedSolutionDir Condition=" '$(OS)' != 'Windows_NT' ">"$(SolutionDir)"</PaddedSolutionDir>

I just reviewed this after coming across this problem and I am confused with the logic of the provided solution above.

Shouldn't you change this:

    <PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT' and HasTrailingSlash('$(SolutionDir)')">"$(SolutionDir)\"</PaddedSolutionDir>
    <PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT' and !HasTrailingSlash('$(SolutionDir)')">"$(SolutionDir)"</PaddedSolutionDir>
    <PaddedSolutionDir Condition=" '$(OS)' != 'Windows_NT' ">"$(SolutionDir)"</PaddedSolutionDir>

...to this:

    <PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT' and HasTrailingSlash('$(SolutionDir)')">"$(SolutionDir)"</PaddedSolutionDir>
    <PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT' and !HasTrailingSlash('$(SolutionDir)')">"$(SolutionDir)\"</PaddedSolutionDir>
    <PaddedSolutionDir Condition=" '$(OS)' != 'Windows_NT' ">"$(SolutionDir)"</PaddedSolutionDir>

If $(SolutionDir) has a trailing slash (i.e. HasTrailingSlash('$(SolutionDir)') == true), you shouldn't be adding a trailing slash to $(SolutionDir). Conversely, if $(SolutionDir) does not have a trailing slash (i.e. !HasTrailingSlash('$(SolutionDir)') == true), you should add a trailing slash to $(SolutionDir).

Right?

@zivkan
Copy link
Member

zivkan commented Nov 21, 2020

@brwertz80 sorry, I missed this back in August. Please review this comment, specifically the "Why NuGet.exe is being called with a space in the SolutionDir path" section.

The generated command line needs the path to have zero or two trailing slashes, but one trailing slash is precisely the cause of the problem.

@brwertz80
Copy link

@brwertz80 sorry, I missed this back in August. Please review this comment, specifically the "Why NuGet.exe is being called with a space in the SolutionDir path" section.

The generated command line needs the path to have zero or two trailing slashes, but one trailing slash is precisely the cause of the problem.

Thanks @zivkan! Took me a bit to remember what I was asking but that makes sense now. 👍

@voam
Copy link

voam commented Dec 3, 2021

Replacing
<PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT'">"$(SolutionDir) "</PaddedSolutionDir>
with
<PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT'">"$(SolutionDir)\"</PaddedSolutionDir>

in NuGet.targets worked for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Functionality:Restore Priority:1 High priority issues that must be resolved in the current sprint. RegressionFromPreviousRTM A regression from the last RTM. Example: worked in 6.2, doesn't work in 6.3 Style:Packages.Config Type:Bug
Projects
None yet
Development

No branches or pull requests

8 participants