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

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

  • 相关阅读:
    Android-TabLayout设置内容宽度以及下划线宽度
    RecyclerView 上拉加载下拉刷新
    Android自定义View实现仿QQ实现运动步数效果
    Android开发中常见的内存泄露案例以及解决方法总结
    Android封装TitleBar基本适用所有常规开发
    Activity设置背景透明之开发坑
    Android表情开发
    订制EditText光标
    Android:java.lang.OutOfMemoryError:GC overhead limit exceeded
    Android之自定义View学习(一)
  • 原文地址:https://www.cnblogs.com/lovecsharp094/p/5551120.html
Copyright © 2011-2022 走看看