File indexing completed on 2024-04-28 16:30:05

0001 #!/usr/bin/env python3
0002 # -*- coding: utf-8 -*-
0003 #***************************************************************************
0004 #* SPDX-FileCopyrightText: 2022 S. MANKOWSKI stephane@mankowski.fr
0005 #* SPDX-FileCopyrightText: 2022 G. DE BURE support@mankowski.fr
0006 #* SPDX-License-Identifier: GPL-3.0-or-later
0007 #***************************************************************************
0008 
0009 import argparse
0010 import datetime
0011 import os
0012 import shutil
0013 import subprocess
0014 import sys
0015 import fileinput
0016 
0017 __VERSION__ = '1.0.0'
0018 
0019 toolPath=os.path.dirname(os.path.realpath(__file__))
0020 localPath=os.path.dirname(toolPath)
0021 tempDir='/data'
0022 
0023 class Releasor(object):
0024     def __init__(self, args):
0025         self.ubuntuVersions=['jammy', 'lunar']
0026         self.workdingDir=os.path.join(tempDir, 'skrooge-release_' + args.version)
0027         print("# Working directory :" + self.workdingDir)    
0028         if args.version.endswith(".0") or args.stable:
0029             self.ppa = "ppa"
0030             self.ppatotreat = ["beta", self.ppa]            
0031         else:
0032             self.ppa = "beta"
0033             self.ppatotreat = [self.ppa]
0034             
0035         if os.path.exists(self.workdingDir):
0036             self.logfile = open(os.path.join(self.workdingDir, 'log.txt'), 'w')
0037         else:
0038             self.logfile = None
0039 
0040     def prepareWorkingDirectory(self, args):
0041         print('# Prepare the working directory')
0042         if os.path.exists(self.workdingDir):
0043             print('#   Remove '+self.workdingDir)
0044             shutil.rmtree(self.workdingDir)
0045         os.mkdir(self.workdingDir)
0046         os.chdir(self.workdingDir)  
0047         
0048         self.logfile = open(os.path.join(self.workdingDir, 'log.txt'), 'w')
0049         print('#   DONE')
0050         return 0
0051         
0052     def makeTarFile(self, args):
0053         rc = 0
0054         if args.fromtar:
0055             print('# Make the tar file from '+args.fromtar)
0056             dst = os.path.join(self.workdingDir, 'skrooge-'+args.version+'.tar.xz')
0057             shutil.copyfile(args.fromtar, dst)
0058             
0059             print('#   DONE')
0060         else:
0061             print('# Make the tar file')
0062             cmd = ['git', 'clone', 'https://github.com/KDE/releaseme.git']
0063             self.logfile.write('### '+' '.join(cmd)+'\n')                
0064             rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)
0065             if rc == 0:
0066                 print('# Launch tarme.rb')
0067                 cmd = ['releaseme/tarme.rb', '--version', args.version, '--origin', 'trunk', 'skrooge']
0068                 self.logfile.write('### '+' '.join(cmd)+'\n')                
0069                 rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)
0070                 
0071                 shutil.rmtree(os.path.join(self.workdingDir, 'skrooge-'+args.version))
0072                 shutil.rmtree('releaseme')
0073                 os.remove(os.path.join(self.workdingDir, 'release_data'))
0074                 sig_file = os.path.join(self.workdingDir, 'skrooge-'+args.version+'.tar.xz.sig')
0075                 if os.path.exists(sig_file):
0076                     os.remove(sig_file)
0077             print('#   '+("DONE" if rc == 0 else "FAILED"))
0078         return rc
0079     
0080     def updateTarFile(self, args):
0081         print('# Update the tar file')
0082         os.chdir(self.workdingDir)  
0083         p = 'skrooge-'+args.version
0084         if os.path.exists(p):
0085             shutil.rmtree(p)
0086         tarfile = 'skrooge-'+args.version+'.tar.xz'
0087         print('#   Untar '+tarfile)
0088         cmd = ['tar', '-xvf', tarfile]
0089         self.logfile.write('### '+' '.join(cmd)+'\n')                
0090         rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)
0091         if rc == 0:
0092             print('#   Change the CMakeLists.txt')
0093             with open(os.path.join(p, 'CMakeLists.txt'), 'r') as fileCMakeLists:
0094                 CMakeListsContent = ''
0095                 for line in fileCMakeLists:
0096                     if line.startswith('SET(SKG_VERSION'):
0097                         print('#     SKG_VERSION changes to "'+args.version+'"')
0098                         CMakeListsContent += 'SET(SKG_VERSION "'+args.version+'")\n'              
0099                     else:
0100                         if line.startswith('SET(SKG_BETA'):
0101                             bb = 'BETA' if self.ppa == "beta" else ''
0102                             print('#     SKG_BETA changes to "'+bb+'"')
0103                             CMakeListsContent += 'SET(SKG_BETA "'+bb+'")\n'              
0104                         else:
0105                             if line.startswith('FEATURE_SUMMARY'):
0106                                 CMakeListsContent += line
0107                                 break
0108                             else:
0109                                 CMakeListsContent += line     
0110             with open(os.path.join(p, 'CMakeLists.txt'), 'w') as fileCMakeLists:
0111                 fileCMakeLists.write(CMakeListsContent)
0112                 
0113             #for line in fileinput.input(['skrooge/org.kde.skrooge.appdata.xml'], inplace=True):
0114             #    print(line.replace('<releases>', '<releases>\n<release version="'+args.version+'" date="'+datetime.datetime.today().strftime('%Y-%m-%d')+'"/>'), end='')
0115             
0116             print('#   Build the new splash screen')
0117             buildPath = os.path.join(p, 'build')
0118             os.mkdir(buildPath)
0119             os.chdir(buildPath) 
0120             cmd = ['cmake', '..', '-DCMAKE_INSTALL_PREFIX=`kf5-config --prefix`', '-DQT_PLUGIN_INSTALL_DIR=`kf5-config --qt-plugins`']
0121             self.logfile.write('### '+' '.join(cmd)+'\n')
0122             rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)
0123             if rc == 0:    
0124                 cmd = ['make', 'splash']
0125                 self.logfile.write('### '+' '.join(cmd)+'\n')                
0126                 rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)
0127                 if rc == 0:                   
0128                     print('#   Create the tar file')
0129                     os.chdir(self.workdingDir)  
0130                     shutil.rmtree(buildPath)
0131                     os.remove(tarfile)
0132                     cmd = ['tar', '-cJf', tarfile, p]
0133                     rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)
0134                     self.logfile.write('### '+' '.join(cmd)+'\n')                                        
0135         if rc == 0:
0136             shutil.rmtree(p)
0137         print('#   '+("DONE" if rc == 0 else "FAILED"))
0138         return rc    
0139     
0140     def generatePublicationMessage(self, args, filename):
0141         cmd = ['gpg2', '--armor', '--detach-sig', '-o', filename+'.sig', filename]
0142         self.logfile.write('### '+' '.join(cmd)+'\n')                
0143         rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)                                  
0144         if rc == 0:
0145             print("Skrooge "+args.version+" released\n\nHi,\n\nCould you publish the following files in "+("stable" if args.stable else "unstable")+"/skrooge ?\n")
0146             cmd = ['sha256sum', filename]
0147             self.logfile.write('### '+' '.join(cmd)+'\n')                
0148             rc = subprocess.call(cmd)  
0149             if rc == 0:
0150                 cmd = ['sha256sum', filename+'.sig']
0151                 self.logfile.write('### '+' '.join(cmd)+'\n')                
0152                 rc = subprocess.call(cmd)  
0153             print("Thank you.\nRegards.\n"   )      
0154     def modify(self, args):
0155         print('# Get dsc')
0156         os.chdir(self.workdingDir)  
0157         cmd = ['apt', 'source', 'skrooge']
0158         self.logfile.write('### '+' '.join(cmd)+'\n')                
0159         rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)
0160         if rc == 0:
0161             previousPackage = [os.path.join(self.workdingDir, o) for o in os.listdir(self.workdingDir) if os.path.isdir(os.path.join(self.workdingDir, o)) and o.startswith('skrooge-')][0]
0162             print('#   previousPackage='+previousPackage)
0163             
0164             os.chdir(previousPackage)  
0165             if os.path.exists('debian'):
0166                 shutil.rmtree('debian')
0167             cmd = ['tar', '-xvf', os.path.join(toolPath, 'skrooge-release-debian.tar.gz')]
0168             self.logfile.write('### '+' '.join(cmd)+'\n')                
0169             rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)
0170             if rc == 0:
0171                 cmd = ['uupdate', '-u', 'skrooge-'+args.version+'.tar.xz']
0172                 self.logfile.write('### '+' '.join(cmd)+'\n')                
0173                 rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)
0174                 if rc == 0:
0175                     # Read the changelog
0176                     os.chdir('../skrooge-'+args.version)
0177                     with open(os.path.join(self.workdingDir, 'skrooge-'+args.version+'/CHANGELOG'), 'r') as fileChangelog:
0178                         fileChangelog.readline() # To pass the first line
0179                         changelogContent = ''
0180                         done = False
0181                         for line in fileChangelog:
0182                             if line.strip() == '' and done == False:
0183                                 changelogContent += ' -- Stephane MANKOWSKI (Perso) <stephane@mankowski.fr>  {}\n'.format(datetime.datetime.now().strftime('%a, %d %b %Y %H:%M:%S +0100'))
0184                                 done = True
0185                             if not line.startswith(' -- '):
0186                                 changelogContent += line  
0187                         
0188                         #
0189                         for ppa in self.ppatotreat:
0190                             for i in range(len(self.ubuntuVersions)):
0191                                 print('#   {}/{}: {} - {}'.format(i+1, len(self.ubuntuVersions), self.ubuntuVersions[i], ppa))
0192                                 f = open(os.path.join(self.workdingDir, 'skrooge-'+args.version+'/debian/control'), 'r')
0193                                 cf = f.read()
0194                                 f.close()
0195                                 
0196                                 #print('#   make changes for '+self.ubuntuVersions[i])
0197                                 #f = open(os.path.join(self.workdingDir, 'skrooge-'+args.version+'/debian/control'), 'w')
0198                                 #f.write(cf.replace('libqjson-dev, \n', '').replace('libqjson0, ', ''))
0199                                 #f.close()                                 
0200                                     
0201                                 with open(os.path.join(self.workdingDir, 'skrooge-'+args.version+'/debian/changelog'), 'w') as fileDebianChangelog:
0202                                     fileDebianChangelog.write('skrooge ('+args.version+'-0ubuntu1~'+ppa+str(i+1)+') '+self.ubuntuVersions[i]+'; urgency=medium\n')
0203                                     fileDebianChangelog.write(changelogContent+'\n')
0204                                     
0205                                     cmd = ['debuild', '-S', '-sa']
0206                                     self.logfile.write('### '+' '.join(cmd)+'\n')                
0207                                     rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)       
0208                                     if rc!=0:
0209                                         break
0210                             if rc!=0:
0211                                 break                                    
0212         print('#   '+("DONE" if rc == 0 else "FAILED"))
0213         return rc      
0214     
0215     def publishLaunchpad(self, args):
0216         print('# Publish on launchpad')
0217         rc = 0
0218         if not args.publish:
0219             print('#   Publication ignored')
0220         os.chdir(self.workdingDir)  
0221         for ppa in self.ppatotreat:
0222             for i in range(len(self.ubuntuVersions)):
0223                 print('#   {}/{}: {} {}'.format(i+1, len(self.ubuntuVersions), self.ubuntuVersions[i], ppa))
0224                 cmd = ['dput', '-f', 'ppa:s-mankowski/'+ppa+'-kf5', 'skrooge_'+args.version+'-0ubuntu1~'+ppa+str(i+1)+'_source.changes']
0225                 if not args.publish:
0226                     print('#     '+' '.join(cmd)+'\n')
0227                 else:
0228                     self.logfile.write('### '+' '.join(cmd)+'\n')                
0229                     rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)       
0230                     if rc!=0:
0231                         break
0232         print('#   '+("DONE" if rc == 0 else "FAILED"))
0233         return rc     
0234     
0235     def publishKDE(self, args):
0236         print('# Publish on kde')
0237         os.chdir(self.workdingDir)  
0238         rc = 0
0239         if not args.publish:
0240             print("#   Publication ignored")
0241         os.chdir(self.workdingDir)  
0242         filename = "skrooge-"+args.version+'-x86_64.AppImage' if args.appimage else "skrooge_"+args.version+'_amd64.snap' if args.snap else 'skrooge-'+args.version+'.tar.xz'
0243         self.generatePublicationMessage(args, filename)   
0244         
0245         cmd = ['kdecp5', filename, 'ftp://upload.kde.org/incoming']
0246         if not args.publish:
0247             print('#     '+' '.join(cmd)+'\n')
0248         else:
0249             self.logfile.write('### '+' '.join(cmd)+'\n')                
0250             rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)       
0251             if rc != 0:
0252                 print("#   "+' '.join(cmd)+" FAILED. Check if already existing")
0253                 
0254             cmd = ['kdecp5', filename + '.sig', 'ftp://upload.kde.org/incoming']
0255             self.logfile.write('### '+' '.join(cmd)+'\n')                   
0256             rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)
0257             if rc != 0:
0258                 print("#   "+' '.join(cmd)+" FAILED. Check if already existing")
0259         print('#   '+("DONE" if rc == 0 else "FAILED"))
0260         return rc    
0261     
0262     def buildAppImage(self, args):
0263         print('# Generate App Image')
0264         os.chdir(self.workdingDir)  
0265         targteappimage = os.path.join(self.workdingDir, "skrooge-"+args.version+'-x86_64.AppImage')
0266         if os.path.exists(targteappimage):
0267             os.remove(targteappimage)  
0268             
0269         cmd = ['wget', '-c', '-nv', 'https://raw.githubusercontent.com/probonopd/AppImages/master/pkg2appimage']
0270         self.logfile.write('### '+' '.join(cmd)+'\n')                
0271         rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)       
0272         if rc == 0:
0273             for line in fileinput.input(['pkg2appimage'], inplace=True):
0274                 if(not 'libcurl-slim' in line):
0275                     print(line, end='')
0276                 
0277             os.chmod('./pkg2appimage', 0o775)
0278                 
0279             if args.fromlocal:
0280                 print('#   Get appimage.yml from local path')
0281                 cmd = ['cp', os.path.join(localPath, 'appimage.yml'), '.']
0282             else:
0283                 cmd = ['wget', '-c', '-nv', 'https://invent.kde.org/office/skrooge/-/raw/master/appimage.yml']
0284             self.logfile.write('### '+' '.join(cmd)+'\n')                
0285             rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)       
0286             if rc == 0:
0287                 if not args.stable:
0288                     for line in fileinput.input(['appimage.yml'], inplace=True):
0289                         print(line.replace('ppa-kf5', 'beta-kf5'), end='')
0290                     
0291                 cmd = ['./pkg2appimage', 'appimage.yml']
0292                 self.logfile.write('### '+' '.join(cmd)+'\n')                
0293                 rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) 
0294                 if rc == 0:                          
0295                     appimage_file = [os.path.join(self.workdingDir, "out/"+o) for o in os.listdir("./out") if o.endswith('.AppImage')][0]
0296                     
0297                     shutil.move(appimage_file, targteappimage)                 
0298         print('#   '+("DONE" if rc == 0 else "FAILED"))
0299         return rc      
0300     
0301     def buildSnap(self, args):
0302         print('# Generate Snap')
0303         os.chdir(self.workdingDir)  
0304         targteappimage = os.path.join(self.workdingDir, "skrooge_"+args.version+'_amd64.snap')
0305         if os.path.exists(targteappimage):
0306             os.remove(targteappimage)  
0307             
0308         if args.fromlocal:
0309             print('#   Get snapcraft.yaml from local path')
0310             cmd = ['cp', os.path.join(localPath, 'snapcraft.yaml'), '.']
0311         else:
0312             cmd = ['wget', '-c', '-nv', 'https://invent.kde.org/office/skrooge/-/raw/master/snapcraft.yaml']
0313         self.logfile.write('### '+' '.join(cmd)+'\n')                
0314         rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile)       
0315         if rc == 0:
0316             for line in fileinput.input(['snapcraft.yaml'], inplace=True):
0317                 print(line.replace('version: "X.X.X"', 'version: "'+args.version+'"').replace('source: XXX', 'source: '+localPath if args.fromlocal else 'source: https://invent.kde.org/office/skrooge.git'), end='')
0318                 
0319             cmd = ['snapcraft']
0320             self.logfile.write('### '+' '.join(cmd)+'\n')                
0321             rc = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile) 
0322         print('#   '+("DONE" if rc == 0 else "FAILED"))
0323         
0324         # TO PUBLISH https://docs.snapcraft.io/build-snaps/c
0325         #      snapcraft push --release=edge skrooge_*.snap
0326         return rc       
0327 
0328 def main():
0329     parser = argparse.ArgumentParser(prog='skrooge-release', description='skrooge release maker')
0330 
0331     # Global arguments
0332     parser.add_argument('--version', required=True,  help='The release version')
0333     parser.add_argument('--fromtar', required=False,  help='To copy an existing tar file instead of building it from git')
0334     parser.add_argument('--pwd', required=False,  help='The password')
0335     parser.add_argument('--stable', action='store_true',  help='To define this version as a master version')
0336     parser.add_argument('--publish', action='store_true',  help='To publish on launchpad and KDE')
0337     parser.add_argument('--appimage', action='store_true',  help='To generate the appimage only')
0338     parser.add_argument('--snap', action='store_true',  help='To generate the snap only')    
0339     parser.add_argument('--fromlocal', action='store_true',  help='To generate The snap and the appimage from local path (' + localPath + ')')    
0340     args = parser.parse_args()
0341     
0342     print("#####################")
0343     print("# Launching release #")
0344     print("#####################")
0345     print("# Version         :" + args.version)
0346     print("# Stable          :" + ("Y" if args.stable else "N"))
0347     print("# Publish         :" + ("Y" if args.publish else "N"))
0348     print("# Appimage        :" + ("Y" if args.appimage else "N"))    
0349     print("# Snap            :" + ("Y" if args.snap else "N"))
0350     if args.fromlocal:
0351         print("# From local path :" + localPath)    
0352     # Launch the release
0353     r = Releasor(args)
0354     rc = 0
0355     rc=r.prepareWorkingDirectory(args)
0356     if(rc == 0 and not (args.appimage or args.snap)): rc=r.makeTarFile(args)
0357     if(rc == 0 and not (args.appimage or args.snap)): rc=r.updateTarFile(args)
0358     if(rc == 0 and not (args.appimage or args.snap)): rc=r.modify(args)
0359     if(rc == 0 and args.appimage): rc=r.buildAppImage(args)
0360     if(rc == 0 and args.snap): rc=r.buildSnap(args)   
0361     if(rc == 0 and not (args.appimage or args.snap)): rc=r.publishLaunchpad(args)
0362     if(rc == 0 and not (args.snap)): rc=r.publishKDE(args)
0363     print("#####################")
0364     print("# End of release    #" if rc == 0 else "# FAILURE         #")
0365     print("#####################")
0366     return rc
0367 
0368 
0369 if __name__ == '__main__':
0370     sys.exit(main())