-
Notifications
You must be signed in to change notification settings - Fork 176
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
WixSharp.Files generation : same folder on different features #48
Comments
I'm not very familiar with fork/pull request, and I prefer to have your opinion. I did a modification to make it work, but I don't know if it impact something or if keep existing folder should not be done for some reason. First, we need to get parent Files.cs: public WixEntity[] GetAllItems(string baseDirectory, Dir parentWixDir) Project.cs:public Project ResolveWildCards(bool ignoreEmptyDirectories = false)
{
int iterator = 0;
var dirList = new List<Dir>();
var fileList = new List<File>();
dirList.AddRange(Dirs);
while (iterator < dirList.Count)
{
foreach (Files dirItems in dirList[iterator].FileCollections)
foreach (WixEntity item in dirItems.GetAllItems(SourceBaseDir, dirList[iterator]))
... I can so check on var subDir = parentDir.Dirs.FirstOrDefault(dir => string.Compare(dir.Name,dirName,ignoreCase: true) == 0 );
if (subDir == null)
{
subDir = new Dir(this.Feature, dirName, new DirFiles(IO.Path.Combine(subDirPath, this.IncludeMask)) ... this modification was done on AgregateSubDirs delegate and on sub dir resolution using System.Linq;
...
public WixEntity[] GetAllItems(string baseDirectory, Dir parentWixDir = null)
{
if (IO.Path.IsPathRooted(Directory))
baseDirectory = Directory;
if (baseDirectory.IsEmpty())
baseDirectory = Environment.CurrentDirectory;
baseDirectory = IO.Path.GetFullPath(baseDirectory);
string rootDirPath;
if (IO.Path.IsPathRooted(Directory))
rootDirPath = Directory;
else
rootDirPath = Utils.PathCombine(baseDirectory, Directory);
Action<Dir, string> AgregateSubDirs = null;
AgregateSubDirs = delegate (Dir parentDir, string dirPath)
{
foreach (var subDirPath in IO.Directory.GetDirectories(dirPath))
{
var dirName = IO.Path.GetFileName(subDirPath);
var subDir = parentDir.Dirs.FirstOrDefault(dir => string.Compare(dir.Name,dirName,ignoreCase: true) == 0 );
if (subDir == null)
{
subDir = new Dir(this.Feature, dirName, new DirFiles(IO.Path.Combine(subDirPath, this.IncludeMask))
{
Feature = this.Feature,
AttributesDefinition = this.AttributesDefinition,
Attributes = this.Attributes,
Filter = this.Filter
});
}
AgregateSubDirs(subDir, subDirPath);
parentDir.Dirs = parentDir.Dirs.Add(subDir);
}
};
var items = new List<WixEntity>
{
new DirFiles(IO.Path.Combine(rootDirPath, this.IncludeMask))
{
Feature = this.Feature,
AttributesDefinition = this.AttributesDefinition,
Attributes = this.Attributes.Clone(),
Filter = this.Filter
}
};
if (!IO.Directory.Exists(rootDirPath))
throw new IO.DirectoryNotFoundException(rootDirPath);
foreach (var subDirPath in System.IO.Directory.GetDirectories(rootDirPath))
{
var dirName = IO.Path.GetFileName(subDirPath);
var subDir = parentWixDir.Dirs.FirstOrDefault(dir => string.Compare(dir.Name, dirName, ignoreCase: true) == 0);
if (subDir == null)
{
subDir = new Dir(this.Feature, dirName, new DirFiles(IO.Path.Combine(subDirPath, this.IncludeMask))
{
Feature = this.Feature,
AttributesDefinition = this.AttributesDefinition,
Attributes = this.Attributes.Clone(),
Filter = this.Filter
});
}
AgregateSubDirs(subDir, subDirPath);
items.Add(subDir);
}
return items.ToArray();
} And finaly In resolve wilcards the WixSharp.Dir is added to full list only if doesn't exist: else if (item is Dir && !dirList[iterator].Dirs.Contains(item))
dirList[iterator].Dirs = dirList[iterator].Dirs.Add(item as Dir); Whole code: public Project ResolveWildCards(bool ignoreEmptyDirectories = false)
{
int iterator = 0;
var dirList = new List<Dir>();
var fileList = new List<File>();
dirList.AddRange(Dirs);
while (iterator < dirList.Count)
{
foreach (Files dirItems in dirList[iterator].FileCollections)
foreach (WixEntity item in dirItems.GetAllItems(SourceBaseDir, dirList[iterator]))
if (item is DirFiles)
dirList[iterator].DirFileCollections = dirList[iterator].DirFileCollections.Add(item as DirFiles);
else if (item is Dir && !dirList[iterator].Dirs.Contains(item))
dirList[iterator].Dirs = dirList[iterator].Dirs.Add(item as Dir);
foreach (Dir dir in dirList[iterator].Dirs)
dirList.Add(dir);
foreach (DirFiles coll in dirList[iterator].DirFileCollections)
dirList[iterator].Files = dirList[iterator].Files.Combine<File>(coll.GetFiles(SourceBaseDir));
//clear resolved collections
dirList[iterator].FileCollections = new Files[0];
dirList[iterator].DirFileCollections = new DirFiles[0];
iterator++;
}
if (ignoreEmptyDirectories)
{
var emptyDirs = AllDirs.Where(d => !d.Files.Any() && !d.Dirs.Any());
emptyDirs.ForEach(emptyDir => AllDirs.ForEach(d =>
{
if (d.Dirs.Contains(emptyDir))
d.Dirs = d.Dirs.Where(x => x != emptyDir).ToArray();
}));
}
return this;
} I have only manually tested it, and it is working. |
Hi there. Thank you for your contribution. I will have a look at this and after the fix you you may not even need to merge your changes. And if your fix is still required then I will help you to create a pull request (or just merge your code directly into In any case I suggest that you wait for me (may be day or two) to let you know my findings. |
Hi, no problem :) Reuse existing folder also cover case where WixSharp.Files resolves same folder with same feature : new Files(feature1, @"Files\Feature1\*"),
new Files(feature2, @"Files\Feature2\*") with new Files(main, @"Files\Feature1\*"),
new Files(main, @"Files\Feature2\*") (and also rename one of "file.txt" or supress ICE30 validation) It is a "developper-friendly" use case, we can merge folders and create wix required folder structure before, with Jenkins for exemple. |
Sorry it took me so long to come back to this one. I had a look at your fix and it seems simple enough. Though it only addresses one problem. Removal of the duplicated Directory elements . It's good as it removes the ICE warning but it also leaves the Features associations broken. Thus a file from that single dir is only associated with a single feature, while your definition associated it with two features. It's not caused by your fix. It is a current limitation of the Wix# wild card support. Thus the direct inclusion of the same files doesn't cause the Features problem problem but ICE30 only. Unfortunately I have to to think abut a proper solution for the File-to-Feature relationship, which is in fact N-to-N. Rolling out your fix as it stand will hide the warning but trigger another hidden problem. Will let you know when I progress with this one. A few useful things to share. :) project.LightOptions += "-sice:ICE30"; When comparing the strings you use var subDir = parentDir.Dirs.FirstOrDefault(dir => dir.Name.SameAs(dirName, ignoreCase: true)); |
Ok, thanks for infos. Sorry I didn't investigate all cases, I was focused on resolving my scenario and I didn't think about others cases. I m working without ICE30 validation from the begining (my project have features which override base files), but even without ICE30 validation, I can't resolve my sample. The id Files.Docs is duplicated. So if I understand, WixSharp use one feature by file/folder, and if same file is resolved by an other feature, it is considered as an other component at wxs generation. But wix can technicaly use same component in different features, which is not the design of wixsharp. The WixSharp approach should work, but if I look at wxs generated by my sample, files ids (and components) are well generated (Component.file.txt and Component.file.txt.1), but dirs ids are not (Files.Docs exists twice, should create Files.Docs.1 ?). Same in Maybe generate different dirs ids can be a workaround? If you really want to handle n-n relationship, I presume you must rewrite Do you think my fix is "useable" if I don't use same files in different features? I really need to resolve my example scenario :) |
This is what I am also wondering. Wix# ID auto-allocation works really well but it doesn't cover Dirs. I just didn't think it was needed. And after today tests with your code I am leaning towards your approach with consolidating the unique dirs. The best way to test is to generate the build batch file with Thus I feel that your solution is good, yes it is "usable" :), even if it has a side effect and I would prefer to fix the side effect directly. Unless of course it becomes over complicated.
Yes it might be. This is what I meant "over complicated". And I really want to avoid this. The solution can be in aggregating the features prior the wxs generation: class File: WixEntity
{
internal Feature[] AllFeatures;
...
// and then instead of
new Dir("Tools",
new File(AllToolsFeature, "logger.exe"),
new File(LightToolsFeature, "logger.exe"),
// use this new API
new Dir("Tools",
new File("logger.exe")
{
AllFeatures = new [] { AllToolsFeature , LightToolsFeature }
... If the new API only involves new members but not new signatures than it is still OK. I really don't want to fiddle with the existing constructors. Will need to sleep on it... |
Done. Actually it was smoother than I anticipated. Thanks to some beneficial design decisions made earlier the solution required minimal changes and the old API is still intact. The fix is effectively your proposed change combined with the extension of the Thus one of your original code snippets will look like this: var main = new Feature("Main");
var feature1 = new Feature("Feature1");
var feature2 = new Feature("Feature2");
...
new Dir(main, @"%ProgramFiles%\My company\My product",
new Files(main, @"Main\*"
...
new Dir("Files",
...
new Files(@"Files\Shared\*"),
{
Features = new [] { feature1, feature2 }
}
)
); Until the new release is available the new version assembly can be downloaded from here: https://github.com/oleg-shilo/wixsharp/blob/master/Source/src/WixSharp.Samples/WixSharp.dll Will wait for a few days for feedback and then will push the new release. |
* Added support for multiple absolute paths. Part of Issue #55 effort. * Issue #55: AbsolutePath support is broken * Issue #48: WixSharp.Files generation: same folder on different features. * Issue #45: Can't install dll to windows/system32 * issues#43: How to mark a .NET assembly to be NGen'd during install * Generic items (`IGenericEntity`) are now allowed in `File` and `Assembly` constructor. * Implemented N-to-N relationship between Wix object/components and `Feature`s. Triggered by issue#48. * [Bootstrapper]support exit code feature * Project Templates extension is migrated to VS2017
Well done! Sorry I was not able to use my computer for many days due to health problem. |
Don't worry. Use your time to recover. For me releasing the fix was important as it addresses that bigger N-to-N issue. And if you still find that it is not fully addressing your issue we will proceed from there. Get well mate. |
Thx man :) Sorry for delay, I m back to work and I lll test this this week. |
No worries, and if there are any problems with the fix we will reopen the issue. |
I have tested it and my scenario doesn't work anymore. All components are referenced in features. I m reading again code posted on github but I m afraid that my last edit on 04/04/2017 post (patch code) was not taken... I probably failed something really sorry for that. I added features to dirs to support empty directories. var subDir = parentDir.Dirs.FirstOrDefault(dir => dir.Name.SameAs(dirName, ignoreCase: true))?? new Dir(dirName);
foreach (var feature in this.ActualFeatures)
{
if (!subDir.ActualFeatures.Contains(feature)) { subDir.Features = subDir.Features.Add(feature); }
}
subDir.AddDirFileCollection(new DirFiles(IO.Path.Combine(subDirPath, this.IncludeMask))
{
Feature = this.Feature,
Features = this.Features,
AttributesDefinition = this.AttributesDefinition,
Attributes = this.Attributes,
Filter = this.Filter
}); |
Txs. I had to bring your changes manually not by pullrequest as I had to modify your changes to coexist with mine. Thus quite possibly I indeed missed some changes. I don't think you did anything wrong :) |
OK, I had a look and indeed your code addresses the rest of the unresolved issues. I only did a slight refactoring of your code: static class CommonTasks
{
static public Dir AddFeatures(this Dir dir, params Feature[] items)
{
...
Dir subDir = parentDir.Dirs.FirstOrDefault(dir => dir.Name.SameAs(dirName, ignoreCase: true)) ?? new Dir(dirName);
subDir.AddFeatures(this.ActualFeatures);
subDir.AddDirFileCollection(... Actually The code is committed. And if you don't want to wait for the release then just grab the binaries from the Samples directory (https://github.com/oleg-shilo/wixsharp/tree/master/Source/src/WixSharp.Samples). Thank you for such a high quality contribution. |
Thanks, WixSharp save a lot of work to me, so I can try to help a little, specially if I need something. It is well documented, well architetured, with few effort we can understand some parts of the code. Continue your good job :) |
👍 I am sincerely glad Wix# gained your appreciation. |
Ok I have tested it with some uses case: updates, modify / repair, with features switch (feature1 installed, upgrade only feature 2 etc) All looks ok!
new Files(feature1, @"Files\Feature1\*"),
new Files(feature2, @"Files\Feature2\*") If a target file is same in 2 features (file.txt): -Install/Update : the last file referenced will be the one selected. -Modify : if you change [feature 1 & 2 was installed] -> modify [feature 1 only] , |
---- * Additional work for Issue #48: WixSharp.Files generation : same folder on different features * Issue #71: Can`t build Wix# Samples\Shortcuts * Fixed an error with path to signtool.exe from ClickOnce's SDK * Issue #74: How to add file into install subdir? * Issue #75: Passing data via SetupEventArgs.Data to AfterInstall handler * Fixed typo in `UnescapeKeyValue` implementation
Is it possible to improve Files resolution to create sub
WiwSharp.Dir
only if not exist?See this simple use case:
Folder structure:
WixSharp Code:
This doesn't work, because "Docs" folder and "file.txt" are created twice.
The text was updated successfully, but these errors were encountered: