zoukankan      html  css  js  c++  java
  • 【NuGet】使用NuGet打包并发布至ProGet过程 (打包再次详解)【下篇】

    一、前言

          上篇[1]主要介绍了利用csproj文件使用NuGet打包至ProGet的过程,并附上了用于在Jenkins上运行的python脚本。本篇的主要内容分为以下几点:

          1. Nuspec与Nupkg的关系

          2. dll文件该如何打包

          3. P4python的几个操作

          4. 融入jenkins

          5. 本周关于与组长的讨论以及生活

    二、Nuspec与Nupkg的关系

          上篇我们说到,nuspec文件是nupkg的清单文件。但是有时候你会发现,明明你的项目里有依赖项(dependency),可你进行nuget spec操作后,发现清单文件里并没有项目中所包含的依赖项,这是为什么?为什么进行nuget pack操作后才会有依赖项,nupkg不是由清单文件nuspec才产生的吗??

          首先,我们想想整个过程。

          第一步,我们进入了项目文件所在的路径,在CMD中执行了nuget spec操作。根据官方文档[2] 这时候其实是你在初始化生成一个清单文件,一些基本的信息都是Token填充的($xxx$这样的),如果你装了Nuget package explorer,双击nuspec你会发现有左右两侧内容,左侧是清单,右侧是package content。而package content中的内容却是你nuspec当前路径下的所有文件。根据官方文档,如果你没提供需要打包的文件,它就会把当前nuspec所在文件夹中的所有内容放在package content中。那为什么之后执行nuget pack又正确的将内容打包了呢?接着往下走。

         第二步,将部分标签的值修改,防止打包失败,例如<tags><description><releaseNotes>,不是默认就行

         第三步,执行nuget pack XXX.csproj操作。这是非常重要的操作,大家都知道csproj文件其实是个xml格式的文件,它会把整个项目的文件信息都以xml的形式记录,在执行这个操作的时候,AssemblyInfo.cs与csproj 文件共同提供信息给nuspec文件,使其清单与打包内容正确,这时候项目中的依赖项就会正确的显示在了包包中。

    三、dll如何打包

         关于dll 打包,这周感慨良多。一开始组长让我搞通打包流程,我用的是csproj的打包方式,然后组长要求必须是dll。这下好,出现思想上的矛盾了。。。

         组长的想法是这样的:

        我的想法是这样的:

        

          大家看到差别了吧,一个是在服务器上已经有一个制作好的nuspec文件,而我只需要在jenkins上执行修改版本号和打包上传即可。另一个是获取dll后,在本地生成nuspec文件再打包上传。看起来好像没什么太大区别哦,其实。。。差的挺多的。组长问,"你怎么知道你打包需要哪些dll?""让需要打包的人告诉我啊"“那好,我再问你,你为什么把需要打包的文件再以脚本方式写入nuspec,这是要干什么” “因为它们要打包在nupkg里啊” “你不会先编辑好nuspec嘛,这么多打包的内容用list写到nuspec里,在jenkins里这么干合适吗?

           其实组长是把打包者与上传者这两个角色进行了拆分,而我是把两者结合在了一起。假设一个打包者把nuspec文件以及相关的dll放在perforce服务器上,jenkins上的每一个人都可以执行打包上传任务,因为他不需要知道nuspec里面的内容,只需要更新个版本号就可以了。相反的,如果在jenkins上操作的并不是打包者,那他并不知道需要打进哪些dll,需要添加或删除哪些依赖项。那他就无法打包了。

          注意:csproj打包方式与dll不同,只要获取csproj文件,就能执行自动化,因为AssemblyInfo.cs以及csproj文件已经能充分提供信息了。

    四、P4python的几个操作

         说实话,p4python官方[3]的几个例子做的有点渣,好歹说一下怎么checkout吧。。。没办法,根据手上现有的资料和网上看看国外的论坛,分享三个比较实用的操作吧。

         (1) 把文件checkout到一个新的changelist中(可不是default哦)

    #checkout到一个新的changelist中
       desc ={"Description":p4description,"Change":"new"}
       p4.input = desc
       info = p4.run("change","-i")
       for s in info:
           changelistNumber =s.split(" ",2)[1]
       changelistId = changelistNumber
    
       checkoutfiles=sys.argv[11]    #checkout的路径
       submittedFiles=[checkoutfiles]   #所需要checkout的文件路径
       for submittedFile in submittedFiles:
            p4.run("edit",["-c"+""+changelistId,submittedFile])
       #checkout

         (2) revertunchangedfiles

    def revertunchangedFile(p4,files):
        try:
            for file in files:
                p4.run("revert",[ "-a",file])
        except Exception as ex:
            return False

         (3) revertfiles

    def revertFile(p4,files):
        try:
            for file in files:
                p4.run("revert",file)
        except Exception as ex:
            return False

    五、融入jenkins

           (1)以csproj的方式打包,重新整理

      1 # coding=gbk
      2 import os
      3 import sys
      4 import re
      5 from P4 import P4
      6 
      7 def getdisc(projectpath):                   #获得项目文件的当前盘
      8     disc = projectpath.split(':', 1)[0]
      9     disc = disc+":"
     10     return disc
     11 
     12 def modifynuspec(projectfilepath,projectname):   #修改nuspec文件内容
     13     tfile = projectfilepath+"\"+projectname+".nuspec"
     14     f = open(tfile,'r')
     15     xmldata = f.read()
     16     xmldata = re.sub('<description>(.*?)</description>', '<description>'+projectname+'</description>', xmldata)
     17     xmldata = re.sub('<tags>(.*?)</tags>', '', xmldata)
     18     xmldata = re.sub('<releaseNotes>(.*?)</releaseNotes>','', xmldata)          #删除里面不用的字段
     19     f.close()
     20     f = open(tfile,'w')
     21     f.write(xmldata)
     22     f.close()
     23 
     24 def autoversion(projectpath):                          #替换版本
     25     assemblyInfoFile = projectpath+"\Properties\AssemblyInfo.cs"
     26     lines= open(assemblyInfoFile, 'r+', encoding='iso-8859-15').readlines()
     27     flen=len(lines)-1
     28     for i in range(flen):
     29          if lines[i].startswith("[assembly: AssemblyVersion"):
     30             versioncode = lines[i].split('"', 2)[1]       #获得当前assemblyinfo的
     31             break
     32     oldVersion = versioncode
     33     splitedVersion = oldVersion.split('.')
     34     lastSubVersion = int(splitedVersion[3])
     35     lastSubVersion += 1
     36     splitedVersion[3] = str(lastSubVersion)
     37     newVersion = '.'.join(splitedVersion)      #将当前的assemblyVersion+1
     38     if not os.path.exists(assemblyInfoFile):
     39        return
     40     fileContent = open(assemblyInfoFile, 'r+', encoding='iso-8859-15').read()
     41     fileContent = fileContent.replace(oldVersion,newVersion)  #把版本替换完重写文件
     42     file = open(assemblyInfoFile,'w+', encoding='iso-8859-15')
     43     file.write(fileContent)
     44     file.flush()
     45     file.close()
     46     return newVersion
     47 
     48 def revertunchangedFile(p4,files):
     49     try:
     50         for file in files:
     51             p4.run("revert",[ "-a",file])
     52     except Exception as ex:
     53         return False
     54 
     55 def revertFile(p4,files):
     56     try:
     57         for file in files:
     58             p4.run("revert",file)
     59     except Exception as ex:
     60         return False
     61 
     62 def  findNugetpack(projectfilepath,searchKeywords):
     63       li = os.listdir(projectfilepath)
     64       for filename in li:
     65           if filename.endswith(".nupkg") and searchKeywords in filename:
     66               nupkgpath = projectfilepath+"\"+ filename
     67               return  nupkgpath
     68 
     69 if __name__ == '__main__':
     70    if len(sys.argv)!=15:
     71        sys.exit(-1)
     72 
     73    #连接P4并同步文件
     74    p4 = P4()
     75    p4.port = sys.argv[1]        #端口号
     76    p4.user =sys.argv[2]         #用户
     77    p4.password = sys.argv[3]    #密码
     78    p4.client =sys.argv[4]       #本地盘
     79    p4.connect()
     80    #连接P4并同步文件
     81 
     82    #打包参数设置
     83    NuGetpath =sys.argv[5]       #NuGet.exe路径
     84    Projectfilepath =sys.argv[6] #项目路径
     85    Projectname =sys.argv[7]     #项目名称
     86    ProGetSourceUrl =sys.argv[8]     #上传的ProGet地址
     87    ProGetAdmin =sys.argv[9]       #ProGet用户名
     88    ProGetPassword =sys.argv[10]     #ProGet密码
     89    #打包参数设置
     90 
     91    p4description = sys.argv[11]   #P4checkout时的描述
     92 
     93    #checkout到一个新的changelist中
     94    desc ={"Description":p4description,"Change":"new"}
     95    p4.input = desc
     96    info = p4.run("change","-i")
     97    for s in info:
     98        changelistNumber =s.split(" ",2)[1]
     99    changelistId = changelistNumber
    100 
    101    checkoutfiles=sys.argv[12]    #checkout的路径
    102    submittedFiles=[checkoutfiles]   #所需要checkout的文件路径
    103    for submittedFile in submittedFiles:
    104         p4.run("edit",["-c"+""+changelistId,submittedFile])
    105    #checkout
    106 
    107    # 改变版本
    108    Newversion = autoversion(Projectfilepath)
    109    # 改变版本
    110 
    111    ProGetAPIKey = sys.argv[13]  #API key
    112    try:
    113       #打包
    114       NuGetdisc = getdisc(NuGetpath)
    115       ProjectDisc = getdisc(Projectfilepath)
    116       Projectnuspec =Projectfilepath+"\"+Projectname+".nuspec"
    117       if not os.path.exists(Projectnuspec):
    118          os.system(''+NuGetdisc+'&&cd '+NuGetpath+'&&nuget setApiKey '+ProGetAPIKey+'')
    119          os.system(''+ProjectDisc+'&&cd '+Projectfilepath+'&&nuget spec')
    120          modifynuspec(Projectfilepath,Projectname)
    121       Projectnamecsproj = Projectname+".csproj"
    122       os.system(''+ProjectDisc+'&&cd '+Projectfilepath+'&&nuget pack '+Projectnamecsproj+' -Build')
    123 
    124       SearchKeywords=sys.argv[14]   #搜索关键词
    125       Nupkgpath = findNugetpack(Projectfilepath,SearchKeywords)
    126       os.system(''+NuGetdisc+'&&cd '+NuGetpath+'&&nuget push '+Nupkgpath+' '+ProGetAPIKey+' -Source '+ProGetSourceUrl+' -ApiKey '+ProGetAdmin+':'+ProGetPassword+'')
    127       #打包
    128 
    129       revertunchangedFile(p4,submittedFiles)
    130       p4.run("change",["-d"],changelistId)
    131    except Exception as ex:
    132         revertFile(p4,submittedFiles)
    133         p4.run("change",["-d"],changelistId)
    134    p4.disconnect()

        

         (2)以dll的方式打包

     1 # coding=gbk
     2 import os
     3 import sys
     4 import re
     5 import xml.dom.minidom
     6 import win32api
     7 
     8 from P4 import P4
     9 
    10 def getdisc(projectpath):                   #获得项目文件的当前盘
    11     disc = projectpath.split(':', 1)[0]
    12     disc = disc+":"
    13     return disc
    14 
    15 def Checknode(filepath,nodename):
    16     dom = xml.dom.minidom.parse(filepath)
    17     root = dom.documentElement
    18     for rt in root.childNodes:
    19       for rt1 in rt.childNodes:
    20         if rt1.nodeName == nodename:
    21            for node in rt1.childNodes:
    22                 return node.nodeValue
    23 
    24 
    25 def getFileVersion(file_name):
    26     info = win32api.GetFileVersionInfo(file_name, os.sep)
    27     ms = info['FileVersionMS']
    28     ls = info['FileVersionLS']
    29     version = '%d.%d.%d.%04d' % (win32api.HIWORD(ms), win32api.LOWORD(ms), win32api.HIWORD(ls), win32api.LOWORD(ls))
    30     return version
    31 
    32 def modifynuspec(projectnuspec,dllfilepath):
    33     tfile = projectnuspec
    34     f = open(tfile,'r')
    35     xmldata = f.read()
    36     #oldversion = Checknode(tfile,"version")  按照默认版本号加1(预留)
    37     #listindex=int(len(oldversion.split("."))-1)
    38     #newversion = int(oldversion.split(".")[listindex])+1
    39     #newversion = oldversion[:-1]+str(newversion)
    40     dllversion = getFileVersion(dllfilepath)  #按照dll版本号
    41     xmldata = re.sub('<version>(.*?)</version>', '<version>'+dllversion+'</version>', xmldata)
    42     f.close()
    43     f = open(tfile,'w')
    44     f.write(xmldata)
    45     f.close()
    46 
    47 def  findNugetpack(nuspecfilepath,searchKeywords):
    48       li = os.listdir(nuspecfilepath)
    49       for filename in li:
    50           if filename.endswith(".nupkg") and searchKeywords in filename:
    51               nupkgpath = nuspecfilepath+"\"+ filename
    52               return  nupkgpath
    53 
    54 
    55 if __name__ == '__main__':
    56    if len(sys.argv)!=13:
    57       sys.exit(-1)
    58 
    59 
    60    #连接P4并同步文件
    61    p4 = P4()
    62    p4.port = sys.argv[1]
    63    p4.user = sys.argv[2]
    64    p4.password = sys.argv[3]
    65    p4.client = sys.argv[4]
    66    p4.connect()
    67    #连接P4并同步文件
    68 
    69    #打包参数设置
    70    NuGetpath =sys.argv[5]
    71    Nuspecfilepath =sys.argv[6]
    72    Nuspecfilename = sys.argv[7]
    73    ProGetSourceUrl = sys.argv[8]
    74    ProGetAdmin =sys.argv[9]
    75    ProGetPassword =sys.argv[19]
    76    ProGetApiKey=sys.argv[11]
    77    #打包参数设置
    78 
    79    #打包
    80    NuGetdisc = getdisc(NuGetpath)
    81    ProjectDisc = getdisc(Nuspecfilepath)
    82    Projectnuspec =Nuspecfilepath+"\"+Nuspecfilename+".nuspec"
    83    Dllfilepath = sys.argv[12]
    84    if  os.path.exists(Projectnuspec):
    85        modifynuspec(Projectnuspec,Dllfilepath)
    86        Projectnuspecname = Nuspecfilename+".nuspec"
    87        os.system(''+ProjectDisc+'&&cd '+ Nuspecfilepath+'&&nuget pack '+Projectnuspecname+'')
    88        Nupkgpath = findNugetpack(Nuspecfilepath,Nuspecfilename)
    89        os.system(''+NuGetdisc+'&&cd '+NuGetpath+'&&nuget push '+Nupkgpath+' '+ProGetApiKey+' -Source '+ProGetSourceUrl+' -ApiKey '+ProGetAdmin+':'+ProGetPassword+'')
    90    else:
    91        sys.exit(-1)
    92    p4.disconnect()

    六、与组长的沟通以及生活

         工作快俩月了。这半个月过得不太顺心,在工作与生活中都意识到了自己的不足。就拿打包这事来说吧,组长本想培养我自我探索自我理清思路的能力,可我只是把每个具体的点搞清楚了,却没有从整体流程去思考,比如dll打包过程中的想法,这是个能力的缺失点。用打刀塔的09的话说“缺少大菊观”。刚进公司我在组A,A组的领导让我实现基本的小模块功能就行,到了组B,开始搞整体流程的时候就蒙蔽了。

        在学校,导师教会了我迎难而上,坚韧不拔的科研精神,因为有时候搞科研就是那一套复杂的方程组,你必须用一些方式去解,没有其他余地。在公司,组长教会了我灵活变通的去解决问题,从一个更高的层次去想每个流程是怎么样的,该以一个最有效率的方法去解决问题,而不是制造问题。

        组长人特别好,每次都不厌其烦的给我洗脑,我挺愧疚的,好多次我都在想为什么不能做的更完美些,然后又给自己挖了个大坑,做了许多重复的事情。组长说,“要当一个有思想的程序员,不然就只是搬代码。很多时候应该想想,我为什么这么做,我做这件的事的意义在哪儿。”

        生活上,这个月感情崩了,该来的还是要来,好聚好散,彼此都祝福了对方。

        这个月唯一的好消息是,毕业前发的一篇SCI总算要出刊了,看到样稿非常开心,特别感谢编辑们的辛勤排版。还有一篇关于算法的SCI还在审。。。都快5个月了我也是醉了。

        最后,感谢我的组长!!!并祝各位博友能一切顺利,人生不如意之事十之八九,还是要以积极心态去面对,我相信只要肯努力,肯动脑,终究会成功的。有什么可以讨论的欢迎留言,多多指教~

    References:

    [1]  http://www.cnblogs.com/lovecsharp094/p/5527204.html

    [2]  https://docs.nuget.org/create/nuspec-reference

    [3]  https://www.perforce.com/perforce/doc.current/manuals/p4script/03_python.html

    作者:airforce094

    出处:http://www.cnblogs.com/lovecsharp094/p/5551120.html

    转载请注明原文出处 , 谢谢合作

  • 相关阅读:
    SharePoint 2013 安装.NET Framework 3.5 报错
    SharePoint 2016 配置工作流环境
    SharePoint 2016 站点注册工作流服务报错
    Work Management Service application in SharePoint 2016
    SharePoint 2016 安装 Cumulative Update for Service Bus 1.0 (KB2799752)报错
    SharePoint 2016 工作流报错“没有适用于此应用程序的地址”
    SharePoint 2016 工作流报错“未安装应用程序管理共享服务代理”
    SharePoint JavaScript API in application pages
    SharePoint 2016 每天预热脚本介绍
    SharePoint 无法删除搜索服务应用程序
  • 原文地址:https://www.cnblogs.com/lovecsharp094/p/5551120.html
Copyright © 2011-2022 走看看