summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xgmm160
1 files changed, 133 insertions, 27 deletions
diff --git a/gmm b/gmm
index 00f040e..44a8297 100755
--- a/gmm
+++ b/gmm
@@ -4,15 +4,25 @@
# Title: Graphical Mount Manager
# Purpose: Easily mount iso files and easily manage these mounted files and mount points, basically like acetoneiso
# Dependencies:
-# req-devuan: python3, python3-psutil
+# req-devuan: python3, python3-psutil, python3-tkstackrpms
# References:
# https://stackoverflow.com/questions/23662280/how-to-log-the-contents-of-a-configparser/50362738#50362738
+# srb_lib/srb_tk.py
+# https://coderslegacy.com/python/list-of-tkinter-widgets/
-import argparse, sys, os, psutil, subprocess, json, configparser
+import argparse, sys, os, psutil, subprocess, json, configparser, tkinter as tk, tkinter.simpledialog
+import tkstackrpms as stk
# LOW-LEVEL values
+appname = "gmm"
appversion = "0.0.1"
-conffile = os.path.join(os.getenv("HOME"),".config","gmm","config")
+conffile = os.path.join(os.getenv("HOME"),".config",appname,"config")
+
+ABOUT_TEXT = """
+gmm "Graphical Mount Manager"
+(C) 2024 bgstack15
+SPDX-License-Identifier: GPL-3.0-only
+"""
# LOW-LEVEL FUNCTIONS
def ferror(*args, **kwargs):
@@ -62,7 +72,7 @@ def list_mounts():
for i in mounts:
if "source" in i:
i.pop("device")
- # Now we have a list of
+ # Now we have a list of
# [{'mountpoint': '/mnt/foo', 'source': '/mnt/public/CDROMs/Games/Logical Journey of the Zoombinis.iso'}]
return mounts
@@ -84,7 +94,7 @@ def mount_iso_to_default(isofile, config = None):
"""
if not config:
raise Exception(f"Fatal: Cannot determine where to mount. Check config file, probably {conffile}.")
- md = config["gmm"]["mounts_dir"]
+ md = config[appname]["mounts_dir"]
# determine next available number. 0-indexed. If you want to make this 1-indexed, set x to 0.
x = -1
safe = False
@@ -179,15 +189,8 @@ def iso_is_mounted_to_path(iso_file, mount_point, mounts = None):
return True
return False
-# GRAPICAL FUNCTIONS
-
-# GRAPHICAL APP
-# want mount iso... file dialog, that has two mimetype choices: *.iso, or *
-# a combo box/list box thing of mounted isos, mount point
-# a config file/dialog for choosing default mounts dir, which is managed by this app. E.g., /mnt/iso so the first disc is /mnt/iso/1 or something. Or ~/mnt/iso. Something like that.
-
# PARSE ARGUMENTS
-parser = argparse.ArgumentParser(description="graphical mount manager",prog="gmm",epilog=""" The value-add of this application is to use a configured directory for
+parser = argparse.ArgumentParser(description="graphical mount manager",prog=appname,epilog=""" The value-add of this application is to use a configured directory for
mountpoints, for easy mounting, e.g., from a graphical file manager. Run with an
iso filename, and it will mount to ~/mnt/0, for example.""")
parser.add_argument("-d","--debug", nargs='?', default=0, type=int, choices=range(0,11), help="Set debug level.")
@@ -217,20 +220,116 @@ show_gui = True
config = configparser.ConfigParser()
if args.conf:
conffile = args.conf
-config.read(conffile)
-try:
- #config["gmm"]["mounts_dir"] = os.path.expanduser(config["gmm"]["mounts_dir"])
- config.set("gmm","mounts_dir", os.path.expanduser(config["gmm"]["mounts_dir"].strip('"')))
-except:
- pass
-if debuglev(9):
- ferror({section: dict(config[section]) for section in config.sections()})
+def load_config(configfile):
+ if debuglev(1):
+ ferror(f"Loading config file {configfile}")
+ config.read(configfile)
+ try:
+ #config["gmm"]["mounts_dir"] = os.path.expanduser(config["gmm"]["mounts_dir"])
+ config.set(appname,"mounts_dir", os.path.expanduser(config[appname]["mounts_dir"].strip('"')))
+ except:
+ pass
+ if debuglev(9):
+ ferror({section: dict(config[section]) for section in config.sections()})
+load_config(conffile)
-# MAIN
+def save_config(configfile):
+ # un-expand the tilde
+ md = config[appname]["mounts_dir"]
+ # by adding the trailing slash, we make sure it is not just the HOME, but that would be an extreme situation.
+ if md.startswith(os.path.expanduser("~")+"/"):
+ md = md.replace(os.path.expanduser("~"),"~")
+ config.set(appname,"mounts_dir",md)
+ with open(configfile,"w") as cf:
+ config.write(cf)
+
+# GRAPHICAL APP
+# want mount iso... file dialog, that has two mimetype choices: *.iso, or *
+# a combo box/list box thing of mounted isos, mount point
+# a config file/dialog for choosing default mounts dir, which is managed by this app. E.g., /mnt/iso so the first disc is /mnt/iso/1 or something. Or ~/mnt/iso. Something like that.
+def NewWindow(textvar, func1, ok_button_func, mounts=None):
+ window = tk.Toplevel()
+ #window.geometry("250x250")
+ window.minsize(100,50)
+ window.title("Settings")
+ #newlabel = tk.Label(window, text="Settings"
+ #newlabel.pack()
+ tk.Label(window, text="Mounts directory").grid(row=0,column=0)
+ ent_mounts_dir = stk.Entry(window,textvariable=textvar,func=func1)
+ ent_mounts_dir.grid(row=0,column=1)
+ tk.Button(window,text="OK",underline=0,command=ok_button_func).grid(row=1,column=1)
+ # WORKHERE: explain why it is disabled to the user
+ if mounts:
+ ent_mounts_dir.configure(state="disabled")
+ return window
+
+class App(tk.Frame):
+ def __init__(self, master):
+ super().__init__(master)
+ # variables
+ self.mounts = list_mounts()
+ self.mounts_dir = tk.StringVar()
+ self.master.title("Graphical Mount Manager")
+ self.master.minsize(250,250)
+ imgicon = stk.get_scaled_icon("dvd_unmount",24,"default","","apps")
+ self.master.tk.call("wm","iconphoto",self.master._w,imgicon)
+ menu = tk.Menu(self.master)
+ menu_file = tk.Menu(menu,tearoff=0)
+ menu_file.add_command(label="Settings...", command=self.func_open_settings, underline=0)
+ menu_file.add_separator()
+ menu_file.add_command(label="Exit", command=self.func_exit, underline=1)
+ menu.add_cascade(label="File",menu=menu_file,underline=0)
+ menu_help = tk.Menu(menu,tearoff=0)
+ menu_help.add_command(label="About", command=self.func_about, underline=0)
+ menu.add_cascade(label="Help",menu=menu_help,underline=0)
+ self.master.config(menu=menu)
+ self.grid() # use this instead of pack()
+ self.background_color = self.master.cget("bg")
+ # initial load
+ self.refresh_form("initial")
+
+# GRAPHICAL FUNCTIONS
+ def func_about(self):
+ """ Display about dialog. """
+ tk.messagebox.Message(title="About",message=ABOUT_TEXT,icon="info").show()
+
+ def func_exit(self):
+ # in case we need to manually do stuff
+ # otherwise command=self.client_exit would have sufficed.
+ self.master.quit()
+
+ def func_open_settings(self):
+ self.settingsWindow = NewWindow(self.mounts_dir,self.save_settings, self.func_close_settings, self.mounts)
+
+ def func_close_settings(self):
+ if debuglev(8):
+ ferror(f"Closing settings window")
+ try:
+ self.settingsWindow.destroy()
+ except Exception as e:
+ ferror(f"DEBUG: when trying to hide settings window, got {e}")
+ self.refresh_form()
+
+ def refresh_form(self,secondObj = None):
+ if debuglev(9):
+ ferror(f"DEBUG: refresh_form got secondObj {secondObj}, class {type(secondObj)}")
+ # compare all config settings to see if they are different
+ load_config(conffile) # this populates object "config"
+ self.mounts_dir.set(config[appname]["mounts_dir"])
+
+ def save_settings(self,secondObj = None):
+ if debuglev(1):
+ ferror(f"DEBUG: saving config file from gui")
+ config.set(appname,"mounts_dir",self.mounts_dir.get())
+ save_config(conffile)
+ self.refresh_form()
+
+
+# MAIN CLI
if "__main__" == __name__:
mounts = list_mounts()
# default behavior is to show the gui, unless --no-gui, or given some paths to mount, or --list
- if (args.gui == False) or (args.list) or (paths):
+ if (args.gui == False) or (args.list) or (paths) or ((not paths) and args.all and umount):
show_gui = False
if args.gui == True:
show_gui = True
@@ -245,7 +344,7 @@ if "__main__" == __name__:
else:
print(mounts)
if paths:
- # calculate if paths.len = 2, then check if paths[0] is a file and paths[1] is a dir or underneath
+ # calculate if paths.len = 2, then check if paths[0] is a file and paths[1] is a dir or underneath
if len(paths) == 2:
left = paths[0]
right = paths[1]
@@ -297,7 +396,14 @@ if "__main__" == __name__:
unmount_iso_to_path(isofile,"")
else:
mount_iso_to_default(isofile,config)
+ else:
+ # no paths, so check if --all and --umount
+ if umount and args.all:
+ for i in mounts:
+ unmount_iso_to_path(i["source"],i["mountpoint"])
+
+ # MAIN GRAPICAL APP
if show_gui:
- # do tkinter app here
- # WORKHERE: entire graphical app
- print(f"STUB DEBUG: please run tkinter app now")
+ root = tk.Tk()
+ gmm_tk = App(root)
+ gmm_tk.mainloop()
bgstack15