views:

867

answers:

5

For some reason, we have a script that creates batch files to XCOPY our compiled assemblies, config files, and various other files to a network share for our beta testers. We do have an installer, but some don't have the permissions required to run the installer, or they're running over Citrix.

If you vomited all over your desk at the mentions of XCOPY and Citrix, use it as an excuse to go home early. You're welcome.

The code currently has hundreds of lines like:

CreateScripts(basePath, "Client", outputDir, FileType.EXE | FileType.DLL | FileType.XML | FileType.CONFIG);

It used to be worse, with 20 int parameters (one per file type) representing whether or not to copy that file type to the output directory.

These hundreds of lines create upload/download batch files with thousands of XCOPY lines. In our setup projects, we can reference things like "Primary output from Client" and "Content Files from Client". I'd love to be able to do that programatically from a non-setup project, but I'm at a loss.

Obviously MS does it, either using an API or by parsing the .csproj files. How would I go about doing this? I'm just looking for a way to get a list of files for any of the setup categories, i.e.:

  • Primary Output
  • Localized Resources
  • Content Files
  • Documentation Files

EDIT: I have a setup project like Hath suggested, and it's halfway to what I'm looking for. The only problem keeping that from being a perfect solution is that multiple projects depend on the same assemblies being in their own folder, and the setup will only copy the file once.

Example:

Projects Admin, Client, and Server all rely on ExceptionHandler.dll, and Admin and Client both rely on Util.dll, while Server does not. This is what I'm looking for:

  • Admin
    • Admin.exe
    • Admin.exe.config
    • ExceptionHandler.dll
    • Util.dll
  • Client
    • Client.exe
    • Client.exe.config
    • ExceptionHandler.dll
    • Util.dll
  • Server
    • Server.exe
    • Server.exe.config
    • ExceptionHandler.dll

Since the referenced assemblies are all the same, what I get is this:

  • Admin
    • Admin.exe
    • Admin.exe.config
    • ExceptionHandler.dll
    • Util.dll
  • Client
    • Client.exe
    • Client.exe.config
  • Server
    • Server.exe
    • Server.exe.config

This causes a FileNotFoundException when either Client or Server can't find one of the two DLLs it's expecting.

Is there a setup property I'm missing to make it always copy the output, even if it's duplicated elsewhere in another project's output?

EDIT AGAIN: All referenced DLLs are set to "Copy Local", and always have been. I found a decent article on using NAnt and XSLT to grab the list of files, so that may be a possible solution as well, as neouser99 suggested.

ACCEPTED SOLUTION: I'm pretty much back where I started. All .exe and .dll outputs are put into a "bin" directory in the setup project, loosely packed. The other per-application folders contain shortcuts to the executable in that directory.

The difference now is, I'm going to add a custom action to the installer to use reflection, enumerate the dependencies for each executable output, and copy the .exe and .dll files to the separate directories. Bit of a pain, as I just assumed there was a way to programatically detect what files would be included via some setup library.

Thanks again for all the help.

+1  A: 

why not use another setup project and just set the 'Package files' setting to As Loose uncompressed files (setup project->properties)? then share the folder.. or something.

edit:

I see, you have 3 folders for your outputs. but the setup project only detects the ExceptionHandler.dll and Util.dll once, so it will just pick the first folder and put it in there.

You could do a setup project for each project - bit annoying maybe..

You could manually add in the dll's to the projects that are missing the assembly's either by adding in the File by 'add file' or 'add assembly' or 'add project output' if you have those projects in the same solution.. (I doubt that's the case though).

or just dump all of them into one output directory...

Hath
It works partially. I've updated the question with the problem I'm running into now.
Chris Doggett
+1  A: 

Although it's designed as a build tool, you might find NAnt to be extremely useful in what you are talking about. The tasks (build, copy, move, delete, etc.) that you can define allow for very fine-grained file lookups, up to general, full folders. If you also incorporate NAnt into your build process, I think you could find that it helps out in more ways then one.

neouser99
Do you have any references or examples of how to get either the content files or project output specifically? I found a decent article regarding it, which I've added to the original post.
Chris Doggett
+1  A: 

Another approach that has worked for me in the past is to add the shared resource (Assembly, DLL or project) as a reference to each of the Admin, Server and Client projects. Then open the properties panel for the referenced item in each project and set "Copy Local" to true.

Now when you build the projects, each will have its own instance of the Assembly copied into its output folder.

This should also cause the shared components added in this manner to be replicated in each of the output folders in the setup package.

Jeff Leonard
All of them are set to "Copy Local", which is how our current XCOPY solution works. Unfortunately, the setup project detects a shared dependency as already existing , so it doesn't copy it to a second folder.
Chris Doggett
A: 

A completely different approach could be to set them up as symbolic links on the network share. A symbolic link is basically a short-cut where the file-system hides the fact that it is a short-cut, so all other applications actually believes that the file has been copied (http://en.wikipedia.org/wiki/NTFS_symbolic_link).

One advantage of this approach is that the file is updated immediately as the file changes and not only when you build your projects. So when you for instance save one of the config-files with a text-editor the update is applied immediately.

Yrlec
A: 

The following MSBuild script part can build your SLN file (you can replace it with .csproj) and will report a list of all projects that were build (Dlls, EXEs).

 <MSBuild Projects="MySolution.sln" Targets="Clean; Rebuild" Properties="Configuration=$(BuildMode);">
    <Output TaskParameter="TargetOutputs"
                ItemName="AssembliesBuilt" />
    </MSBuild>

Now, this doesn't really solve your problem, but it gets you a list of everything that was build. You also have copylocal, so you could probably just take AssembiesBuild and copy all DLL and .CONFIG files from there.

Example:

AssembliesBuild = c:\myproj\something1\build.dll

you'd go to c:\myproj\something1\ and simply search for all *.dll and *.config files and include them. You can do this pretty easily with MSBuild or powershell, if you have it installed. To output a XCOPY script from MSBuild, I think you'll need MSBuild contrib projct installed.

bh213