""" * Author: "PepDebian(peppermintosteam@proton.me) * * License: SPDX-License-Identifier: GPL-3.0-or-later * * This script is used as an update gui manager """ import tkinter as tk import subprocess import os import shutil import sqlite3 import filecmp from tkinter import Frame from threading import Thread import ttkbootstrap as ttk from crontab import CronTab from git import Repo from ttkbootstrap.scrolled import ScrolledText from ttkbootstrap.constants import HORIZONTAL import bsconf # setup the window pwin = bsconf.bbstyle pwin.title('Peppermint Update Manager') pwin.tk.call('wm', 'iconphoto', pwin._w, tk.PhotoImage( file='/usr/share/pixmaps/peppermint-old.png')) pwin['bg'] = '#000000' WINDOW_HEIGHT = 630 WINDOW_WIDTH = 750 # set the database connection string dcon = sqlite3.connect('/opt/pypep/dbpep/welval.db') pcur = dcon.cursor() # Create the update table pcur.execute(""" CREATE TABLE IF NOT EXISTS upsched (id integer PRIMARY KEY AUTOINCREMENT, dname text, cronnum int, hr int, min int);""") # The Functions def center_screen(): """ gets the coordinates of the center of the screen """ screen_width = pwin.winfo_screenwidth() screen_height = pwin.winfo_screenheight() # Coordinates of the upper left corner of the window to make the window # appear in the center x_cordinate = int((screen_width / 2) - (WINDOW_WIDTH / 2)) y_cordinate = int((screen_height / 2) - (WINDOW_HEIGHT / 2)) pwin.geometry("{}x{}+{}+{}".format(WINDOW_WIDTH, WINDOW_HEIGHT, x_cordinate, y_cordinate)) def drepo(): """Delete the temp repo files.""" fld = '/opt/tmprpo/' for filename in os.listdir(fld): fp = os.path.join(fld, filename) try: if os.path.isfile(fp) or os.path.islink(fp): os.unlink(fp) elif os.path.isdir(fp): shutil.rmtree(fld) except Exception as e: print('Failed to delete %s. Reason: %s' % (fp, e)) def cbclone(): """Clones the Production Tools Repo locally""" repo_url = 'https://codeberg.org/Peppermint_OS/PepProTools.git' repo_path = '/opt/tmprpo/' if os.path.exists(repo_path): shutil.rmtree(repo_path) else: os.makedirs(repo_path) Repo.clone_from(repo_url, repo_path) def checkfiles(): """Compare the repo files downloaded with what is in opt and detemrine if an update is needed """ b = '/opt/pypep/' a = '/opt/tmprpo/' comp = filecmp.dircmp(a, b) common = sorted(comp.common) left = sorted(comp.left_list) right = sorted(comp.right_list) if left != common or right != common: file_names = os.listdir(a) for file_name in file_names: if file_name.endswith(".git"): pass else: shutil.copy(os.path.join(a, file_name), b) else: pass def updtpeptools(): """brings all the update tool functions together""" terminalstuff.delete(1.0) pwin.update() msg1 = ''' Checking Codeberg for updates''' terminalstuff.insert('end', msg1) pwin.update() cbclone() msg2 = ''' Applying updates''' terminalstuff.insert('end', msg2) pwin.update() checkfiles() msg3 = ''' Cleaning up....''' terminalstuff.insert('end', msg3) pwin.update() drepo() message = ''' PepTools updated! Check out PepScope to review the changes''' terminalstuff.insert('end', message) pwin.update() def pu(cmd, terminal): """set up the pipe process.""" # set thecompleted message pepipe = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, bufsize=1, universal_newlines=True, shell=True) pepipe.poll() while True: line = pepipe.stdout.readline() terminal.insert(tk.END, line) terminal.see(tk.END) if not line and pepipe.poll is not None: break commsg = '''Completed!''' terminalstuff.insert('end', commsg) def peppersys(): """ This will apt command and send the results to the terminal textbox """ sysu = "apt update && apt upgrade -y" pepper = Thread(target=lambda: pu(sysu, terminalstuff)) pepper.start() terminalstuff.delete(1.0, END) def ldsettings(): """Preset the update options based on what is stored in the database""" # set the connector dbst = sqlite3.connect('/opt/pypep/dbpep/welval.db') mvar = "Mon" tuvar = "Tue" wvar = "Wed" tvar = "Thu" fvar = "Fri" savar = "Sat" suvar = "Sun" # set the queries cbval = """ SELECT COUNT(*) FROM upsched WHERE dname = ?;""" hval = """ SELECT hr FROM upsched WHERE hr IS NOT NULL;""" hcval = """ SELECT COUNT(*) FROM upsched WHERE hr IS NOT NULL;""" mval = """ SELECT min FROM upsched WHERE min IS NOT NULL;""" mcval = """ SELECT COUNT(*) FROM upsched WHERE min IS NOT NULL;""" # set the cursor to be used for execution dcur = dbst.cursor() # Start the hr call dcur.execute(hcval) hrc = dcur.fetchone() if int(hrc[0]) > 0: # If there is a hour value in the databes set the texbox # widget to that value. dcur.execute(hval) hsel = dcur.fetchone() txtopthour.insert(0, hsel) else: # if there is no value print this message and pass. print('No hour value is there') # Start the minute call dcur.execute(mcval) minc = dcur.fetchone() if int(minc[0]) > 0: # If there is a minute value in the databes set the texbox # widget to that value. dcur.execute(mval) msel = dcur.fetchone() txtoptmin.insert(0, msel) else: # if there is no value print this message and pass. print('No minute value is there') ##Start text box settings...## # Monday dcur.execute(cbval, (mvar,)) mr = dcur.fetchone() if int(mr[0]) > 0: # if the cbval is in the DB then print and set the checkbutton # value cbm_v.set(1) print("Mon is there") else: # If the cbval is 0 then print this message print('Nothing There') #Tue## dcur.execute(cbval, (tuvar,)) tur = dcur.fetchone() if int(tur[0]) > 0: cbtu_v.set(1) print("Tue is there") else: print('Nothing There') ##Wed## dcur.execute(cbval, (wvar,)) wr = dcur.fetchone() if int(wr[0]) > 0: cbw_v.set(1) print("Wed is there") else: print('Nothing There') ##Thu## dcur.execute(cbval, (tvar,)) tr = dcur.fetchone() if int(tr[0]) > 0: cbt_v.set(1) print("Thu is there") else: print('Nothing There') ##Fri## dcur.execute(cbval, (fvar,)) fr = dcur.fetchone() if int(fr[0]) > 0: cbf_v.set(1) print("Fri is there") else: print('Nothing There') ##Sat## dcur.execute(cbval, (savar,)) sar = dcur.fetchone() if int(sar[0]) > 0: cbsa_v.set(1) print("Sat is there") else: print('Nothing There') ##Sun## dcur.execute(cbval, (suvar,)) sur = dcur.fetchone() if int(sur[0]) > 0: cbsu_v.set(1) print("Sun is there") else: print('Nothing There') def pcron(): """This will set ccron table schedule to run updates""" cron = CronTab(user='root') # get the value that is entered in the hour text box # it must be with 0 to 24 other wise it is out of range # then see if the hour is already in the DB if it is # delete it and add in the new value from the text box # else its a new record and you just need to add it # set the connector db = sqlite3.connect('/opt/pypep/dbpep/welval.db') # set the cursor dbcur = db.cursor() # This section will save the hour values entered in the database hrtx = txtopthour.get() if len(hrtx) == 0: # If nothing was entered then print the message and pass the if print('nothing entered') else: # if there is a value then delete it first then add the record # other wise just add the record. hra = int(hrtx) if 0 <= hra <= 24: hval = """ SELECT COUNT(*) FROM upsched WHERE hr IS NOT NULL; """ hdel = """ DELETE FROM upsched WHERE hr IS NOT NULL; """ hrinsrt = """ INSERT INTO upsched (hr) VALUES (?); """ harg = hra dbcur.execute(hval) crresult = dbcur.fetchone() if int(crresult[0]) > 0: dbcur.execute(hdel) db.commit() dbcur.execute(hrinsrt, (harg,)) db.commit() print(hra) else: dbcur.execute(hrinsrt, (harg,)) db.commit() else: print('out of range') # Same process for the Minute its a repeate as above but for the # Minute text widget mitx = txtoptmin.get() if len(mitx) == 0: print('nothing entered') else: mia = int(mitx) if 0 <= mia <= 24: mval = """ SELECT COUNT(*) FROM upsched WHERE min IS NOT NULL; """ mdel = """ DELETE FROM upsched WHERE min IS NOT NULL; """ miinsrt = """ INSERT INTO upsched (min) VALUES (?); """ marg = mia dbcur.execute(mval) crresult = dbcur.fetchone() if int(crresult[0]) > 0: dbcur.execute(mdel) db.commit() dbcur.execute(miinsrt, (marg,)) db.commit() print(mia) else: dbcur.execute(miinsrt, (marg,)) db.commit() else: print('out of range') # these are the days of the week checkbuttons if they are on or # off do something # var the message to print in terminal alrdy = "There is already a value for that day," # set the variables used for the SQL queries mvar = "Mon" tuvar = "Tue" wvar = "Wed" tvar = "Thu" fvar = "Fri" savar = "Sat" suvar = "Sun" # set the queries cval = """ SELECT COUNT(*) FROM upsched WHERE dname = ?;""" dinsrt = """ INSERT INTO upsched(dname) VALUES (?);""" drmv = """ DELETE FROM upsched WHERE dname = ?;""" if cbm_v.get() == 1: # run the query withthe variable dbcur.execute(cval, (mvar,)) # get the result crresult = dbcur.fetchone() if int(crresult[0]) > 0: # if the value is in the DB then print print(alrdy, "Mon") else: # if it is not in the DB then add it dbcur.execute(dinsrt, (mvar,)) db.commit() print('Mon Added to Database') # Create the new job jobm = cron.new( command='/bin/sh opt/pypep/pepwork.sh', comment='Monday') # Set the value to what is in the hour textbox jobm.hour.on(hra) # Set the value to what is in the minute textbox jobm.minute.on(mia) # set the day of the week jobm.dow.on('1') # Write the job to the crontab cron.write() # Show the job was witten print('wrote cron') # list the jobs in the terminal for jobm in cron: print(jobm) # this is the finish monday function print('mon is on') else: # If unchecked Remove the current day value if cbm_v.get() == 0: dbcur.execute(cval, (mvar,)) mdelresult = dbcur.fetchone() if int(mdelresult[0]) > 0: # run the delete query dbcur.execute(drmv, (mvar,)) # commit the change to the database db.commit() # set what job to find in the crontab jobm = cron.find_comment('Monday') # Clear and write the contab cron.remove(jobm) cron.write() # print that the cron job was deleted print('Mon Cron Deleted') # print the Record was deleted from the Databaes print('Mon was deleted from db becuase the cb is off') else: # Print nothing deleted if nothing was found print('nothing to delete') # pring that that the check box is off. print('mon is off') if cbtu_v.get() == 1: dbcur.execute(cval, (tuvar,)) crresult = dbcur.fetchone() if int(crresult[0]) > 0: print(alrdy, "Tue") else: dbcur.execute(dinsrt, (tuvar,)) db.commit() print('Tue Added to Database') jobtu = cron.new( command='/bin/sh opt/pypep/pepwork.sh', comment='Tuesday') jobtu.hour.on(hra) jobtu.minute.on(mia) jobtu.dow.on(2) cron.write() for jobtu in cron: print(jobtu) print('wrote cron') print('tue is on') else: if cbtu_v.get() == 0: dbcur.execute(cval, (tuvar,)) tudelresult = dbcur.fetchone() if int(tudelresult[0]) > 0: dbcur.execute(drmv, (tuvar,)) db.commit() jobtu = cron.find_comment('Tuesday') cron.remove(jobtu) cron.write() print('Tue Cron Deleted') print('Tue was deleted from db becuase the cb is off') else: print('nothing to delete') print('tue is off') if cbw_v.get() == 1: dbcur.execute(cval, (wvar,)) crresult = dbcur.fetchone() if int(crresult[0]) > 0: print(alrdy, "Wed") else: dbcur.execute(dinsrt, (wvar,)) db.commit() print('Wed Added to Database') jobw = cron.new( command='/bin/sh opt/pypep/pepwork.sh', comment='Wednesday') jobw.hour.on(hra) jobw.minute.on(mia) jobw.dow.on(3) cron.write() print('wrote cron') print('wed is on') else: if cbw_v.get() == 0: dbcur.execute(cval, (wvar,)) wdelresult = dbcur.fetchone() if int(wdelresult[0]) > 0: dbcur.execute(drmv, (wvar,)) db.commit() jobw = cron.find_comment('Wednesday') cron.remove(jobw) cron.write() print('Wed Cron Deleted') print('Wed was deleted from db becuase the cb is off') else: print('nothing to delete') print('wed is off') if cbt_v.get() == 1: dbcur.execute(cval, (tvar,)) crresult = dbcur.fetchone() if int(crresult[0]) > 0: print(alrdy, "Thu") else: dbcur.execute(dinsrt, (tvar,)) db.commit() print('Thu Added to Database') jobt = cron.new( command='/bin/sh opt/pypep/pepwork.sh', comment='Thursday') jobt.hour.on(hra) jobt.minute.on(mia) jobt.dow.on(4) cron.write() print('wrote cron') print('thu is on') else: if cbt_v.get() == 0: dbcur.execute(cval, (tvar,)) tdelresult = dbcur.fetchone() if int(tdelresult[0]) > 0: dbcur.execute(drmv, (tvar,)) db.commit() jobt = cron.find_comment('Thursday') cron.remove(jobt) cron.write() print('Thu Cron Deleted') print('Thu was deleted from db becuase the cb is off') else: print('nothing to delete') print('thu is off') if cbf_v.get() == 1: dbcur.execute(cval, (fvar,)) crresult = dbcur.fetchone() if int(crresult[0]) > 0: print(alrdy, "Fri") else: dbcur.execute(dinsrt, (fvar,)) db.commit() print('Fri Added to Database') jobf = cron.new( command='/bin/sh opt/pypep/pepwork.sh', comment='Friday') jobf.hour.on(hra) jobf.minute.on(mia) jobf.dow.on(5) cron.write() print('wrote cron') print('fri is on') else: if cbf_v.get() == 0: dbcur.execute(cval, (fvar,)) fdelresult = dbcur.fetchone() if int(fdelresult[0]) > 0: dbcur.execute(drmv, (fvar,)) db.commit() jobf = cron.find_comment('Friday') cron.remove(jobf) cron.write() print('Fri Cron Deleted') print('Fri was deleted from db becuase the cb is off') else: print('nothing to delete') print('fri is off') if cbsa_v.get() == 1: dbcur.execute(cval, (savar,)) crresult = dbcur.fetchone() if int(crresult[0]) > 0: print(alrdy, "Sat") else: dbcur.execute(dinsrt, (savar,)) db.commit() print('Sat Added to Database') jobsa = cron.new( command='/bin/sh opt/pypep/pepwork.sh', comment='Saturday') jobsa.hour.on(hra) jobsa.minute.on(mia) jobsa.dow.on(6) cron.write() print('wrote cron') print('sat is on') else: if cbsa_v.get() == 0: dbcur.execute(cval, (savar,)) sadelresult = dbcur.fetchone() if int(sadelresult[0]) > 0: dbcur.execute(drmv, (savar,)) db.commit() jobsa = cron.find_comment('Saturday') cron.remove(jobsa) cron.write() print('Sat Cron Deleted') print('Sat was deleted from db becuase the cb is off') else: print('nothing to delete') print('sat is off') if cbsu_v.get() == 1: dbcur.execute(cval, (suvar,)) crresult = dbcur.fetchone() if int(crresult[0]) > 0: print(alrdy, "Sun") else: dbcur.execute(dinsrt, (suvar,)) db.commit() print('Sun Added to Database') jobsu = cron.new( command='/bin/sh opt/pypep/pepwork.sh', comment='Sunday') jobsu.hour.on(hra) jobsu.minute.on(mia) jobsu.dow.on(0) cron.write() for job in cron: print(job) print('wrote cron') print('sun is on') else: if cbsu_v.get() == 0: dbcur.execute(cval, (suvar,)) sudelresult = dbcur.fetchone() if int(sudelresult[0]) > 0: dbcur.execute(drmv, (suvar,)) db.commit() jobsu = cron.find_comment('Sunday') cron.remove(jobsu) cron.write() print('Sun Cron Deleted') print('Sun was deleted from db because the cb is off') else: print('nothing to delete') print('sun is off') pwin.destroy() # notebook stuff pnb = ttk.Notebook(pwin, bootstyle="danger") pnb.pack(pady=10, expand=True) fnb1 = ttk.Frame(pnb, width=400, height=400) fnb2 = ttk.Frame(pnb, width=400, height=400) fnb1.pack(fill='both', expand=True) fnb2.pack(fill='both', expand=True) pnb.add(fnb1, text='Update Manager') pnb.add(fnb2, text='Options') # frames to use separate parts of the window fbset0 = Frame(fnb1) fbset0.pack(side="top") fbset1 = Frame(fnb1) fbset1.pack(side="top") fbset3 = Frame(fnb1) fbset3.pack(side="top") fbset2 = Frame(fnb1) fbset2.pack(side="top") fbset4 = Frame(fnb1) fbset4.pack(side="top") fterm = Frame(fnb1) fterm.pack(side="top", fill="both", expand=True) # These lables provide space in betweenthe buttons # Using pack on the Update manager tab lbltitle = ttk.Label(fbset0) lbltitle.pack() lbltitle = ttk.Label(fbset3) lbltitle.pack() lbltitle = ttk.Label(fbset4) lbltitle.pack() # Holds the terminal output terminalstuff = ScrolledText(fterm, padding=5, bootstyle="dark") terminalstuff.pack(fill="both", expand=True) # The things that are used on the Update Manager Tab sysupdtbtn = ttk.Button( fbset1, text="System Updates", width=20, cursor="hand2", bootstyle="light-outline", command=peppersys) sysupdtbtn.pack(side="left") ptupdtbtn = ttk.Button( fbset1, text="Update Pep Tools", width=20, cursor="hand2", bootstyle="light-outline", command=updtpeptools) ptupdtbtn.pack(side="left") lblumsg = ttk.Label( fbset2, text="Use the buttons to update your tools or system", bootstyle="inverse-light") lblumsg.pack() # the things that are used on the Options tab # The title of the Peppermint Tools Section lblopttitle = ttk.Label( fnb2, text="Set a schedule for Peppermint tools", bootstyle="inverse-light") lblopttitle.place(x=10, y=15) # First one below the Peppermint tools title sepoptlt = ttk.Separator(fnb2, bootstyle="danger", orient=HORIZONTAL) sepoptlt.place(x=10, y=40, relwidth=1) # Second one below the System Updates sepopbtm = ttk.Separator(fnb2, bootstyle="danger", orient=HORIZONTAL) sepopbtm.place(x=10, y=140, relwidth=1) # The last one right above the information sepopend = ttk.Separator(fnb2, bootstyle="danger", orient=HORIZONTAL) sepopend.place(x=10, y=240, relwidth=1) cbm_v = tk.IntVar() cbm = ttk.Checkbutton(fnb2, text="Mon", variable=cbm_v, bootstyle="success-round-toggle") cbm.place(x=10, y=180) cbtu_v = tk.IntVar() cbtu = ttk.Checkbutton( fnb2, text="Tue", variable=cbtu_v, bootstyle="success-round-toggle") cbtu.place(x=80, y=180) cbw_v = tk.IntVar() cbw = ttk.Checkbutton(fnb2, text="Wed", variable=cbw_v, bootstyle="success-round-toggle") cbw.place(x=160, y=180) cbt_v = tk.IntVar() cbt = ttk.Checkbutton(fnb2, text="Thu", variable=cbt_v, bootstyle="success-round-toggle") cbt.place(x=240, y=180) cbf_v = tk.IntVar() cbf = ttk.Checkbutton(fnb2, text="Fri", variable=cbf_v, bootstyle="success-round-toggle") cbf.place(x=10, y=210) cbsa_v = tk.IntVar() cbsa = ttk.Checkbutton( fnb2, text="Sat", variable=cbsa_v, bootstyle="success-round-toggle") cbsa.place(x=80, y=210) cbsu_v = tk.IntVar() cbsu = ttk.Checkbutton( fnb2, text="Sun", variable=cbsu_v, bootstyle="success-round-toggle") cbsu.place(x=160, y=210) # lets the user know the schedule will start from the selected date lbloptdys = ttk.Label(fnb2, text="Select the days you want") lbloptdys.place(x=10, y=150) lblopttime = ttk.Label(fnb2, text="Select the time you want") lblopttime.place(x=10, y=50) lblopttimehr = ttk.Label(fnb2, text="hr") lblopttimehr.place(x=17, y=80) lblopttimemin = ttk.Label(fnb2, text="min") lblopttimemin.place(x=66, y=80) txtopthour = ttk.Entry(fnb2, bootstyle="danger", width=2) txtopthour.place(x=10, y=100) lblopttimecl = ttk.Label(fnb2, text=":") lblopttimecl.place(x=50, y=105) txtoptmin = ttk.Entry(fnb2, bootstyle="danger", width=2) txtoptmin.place(x=66, y=100) # this is the information section explaining what this application does. # The frame that holds the message instfr = ttk.Labelframe(fnb2, bootstyle="danger", text='Information') instfr.place(x=10, y=270) # The message lblinstpt = ttk.Label( instfr, text="When you set a schedule for the Peppermint tools, the updater" " will check the git repos for any new updates that may be" " available and install them. Addtionally System Updates" " will check the Debian or Devuan repos depending on what spin" " of Peppermint you are running ", wraplength=600) lblinstpt.pack(side="top", pady=5, padx=5) btnpt = ttk.Button( fnb2, text="Save & Exit", cursor="hand2", bootstyle="light-outline", command=pcron) btnpt.place(x=500, y=500) # call Center screen center_screen() ldsettings() pwin.mainloop()