代码改变世界

Wix 安装部署教程(十二) -- 自动更新WXS文件

2015-08-06 22:08  stoneniqiu  阅读(2619)  评论(2编辑  收藏  举报

        上一篇分享了一个QuickWIX,用来对比两个工程前后的差异,但是这样还是很繁琐,而且昨天发现有Bug,目录对比有问题。这次改变做法,完全让程序自动去更新WXS文件,然后再用CCNet去自动编译,这样的话,工程师更新文件,再也不用我去编译,发布了。

         思路:在原来的基础上,传入工程路径和目标文件夹,用模板的方式,更新变动的部分生成新的WXS文件覆盖原来的文件,一开始我思路搞错了,想在比较的基础上去更新变动的部分,比如一个文件删除了,就把这个File移除掉,同理对于组件和目录,但是这样比较费事,容易出Bug。

         工程目录,在原来的基础上没有增加对象。多了一个Templet文件,用于放模板文件。

         

     界面:

     

          如果改成控制台程序,就三句:     

 static void Main(string[] args)
        {
            if (args.Length < 2)
                return;
            Console.WriteLine(args[0]);
            Console.WriteLine(args[1]);
            var wiXml = new GenerateWiXml(args[0], "$(var.Dev)", args[1]);
            wiXml.Generate();
            wiXml.WixComparator.AfterWixProj.SaveAsLast();
            Console.WriteLine("替换完成");
        }

先创建GenrateWiXml对象,调用Generate方法来根据目录来生成WIX元素。每个元素都有ToWixString方法。  主要是SaveAsLast方法,更换了两个WXS文件。Product.wxs和DevComponents.wxs。前者找Feature 和 Directory 标签,后者分两种情况,根目录和其他目录,因为我根目录文件夹写了些其他的元素,不能全部替换Files,另外其他的DirectoryRef 就直接添加了。

 public void SaveAsLast()
        {
            #region DirAndCompDocument
            if (DirAndCompDocument == null)
            {
                DirAndCompDocument = XDocument.Load(GetWxsProductPath());
            }

            var rawpath1 = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + @"..\..\Templet\", WixConfig.WxsProductPath);
            var productTemp = XDocument.Load(rawpath1);
            // 组件
            var comelement = WixFeature.NewXElement();
            var feature = productTemp.Descendants()
                            .First()
                            .Elements()
                            .First()
                            .Elements()
                            .FirstOrDefault(n => n.Name == WixConfig.Np + "Feature" && n.Attribute("Id").Value == "ProductFeature");

            if (feature != null)
            {
                feature.Elements().Remove();
            
                feature.Add(comelement.Elements());
            }
            // 目录
            var direlement = WixDirectory.NewXElement();

            var element = productTemp.Descendants()
                  .First()
                  .Elements()
                  .First()
                  .Elements()
                  .FirstOrDefault(n => n.Name == WixConfig.Np + "Directory");
            if (element != null)
            {
                var dir = element.Elements().First();
                dir.Elements().Remove();
                dir.Add(direlement.Elements());
            }


            productTemp.Save(GetWxsProductPath());

            #endregion 

            #region files
            var rawpath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + @"..\..\Templet\", WixConfig.WxsFilePath);
            var dirTemp = XDocument.Load(rawpath);
            var fragment = dirTemp.Descendants().First().Elements().First();
            var installfolder = WixFragment.DirectoryRefs;
            //根目录下面的dir 都要递归处理 要全部加到DirTemp中去
            foreach (var wd in installfolder)
            {
                //最特别的一个
                if (wd.Id == "INSTALLFOLDER")
                {
                    //找到Install下面的comp 全部加进来
                    var firstcop = fragment.Elements().First().Elements().First();
                    foreach (var file in wd.Component.Files)
                    {
                        firstcop.Add(file.XElement);
                    }
                }
                else
                {
                    //全部添加   
                    fragment.Add(wd.XElement);
                }

            }
            dirTemp.Save(GetWxsFilePath());


            #endregion


        }

 这个WXS模板,需要自己调整了。而每个元素的XElement基本上是这样生成的(WIXDirectoryRef):

              if (_xElement == null)
                {
                    XNamespace np = "http://schemas.microsoft.com/wix/2006/wi";
                    var str = ToWixString();
                    _xElement = XElement.Parse(str);
                    _xElement.Name = np + "DirectoryRef";
                    // 确保后代的命名空间都对
                    var cops = _xElement.Elements();
                    foreach (var xe in cops)
                    {
                        xe.Name = np + "Component";

                        foreach (var x in xe.Elements())
                        {
                            x.Name = np + "File";
                        }
                    }
                }

调用XElement的Parse方法后,需要修改元素的命名空间,不然每个元素都会出现一个xmlns=“”的标签。

     小结:将上面的工程改成控制台配合自己的WIX的SetUp工程,然后部署到CCNET就可以自动打包了。以下是源码,比较部分替换元素的代码没有删除,先留着。希望对你有帮助。 

 http://pan.baidu.com/s/1hUtki