File indexing completed on 2024-05-12 13:15:16
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())