一、前言
上篇[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
转载请注明原文出处 , 谢谢合作