forked from cmccabe/linkulator2
Some user settings can be read and saved to a config file
This commit is contained in:
parent
b736cd0b6e
commit
e9df516ef5
102
config.py
102
config.py
|
@ -1,25 +1,93 @@
|
|||
"""stores configuration settings for linkulator"""
|
||||
import json
|
||||
import stat
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
|
||||
|
||||
class DefaultConfigOptions:
|
||||
"""data class for configuration options"""
|
||||
class DefaultPaths:
|
||||
"""data class containing configurable path defaults"""
|
||||
|
||||
all_homedir_pattern: str
|
||||
datadir: str
|
||||
datafile: str
|
||||
ignorefile: str
|
||||
my_datadir: Path
|
||||
my_datafile: Path
|
||||
my_ignorefile: Path
|
||||
all_homedir_pattern: str = "/home/*/"
|
||||
datadir: str = ".linkulator"
|
||||
datafile: str = "linkulator.data"
|
||||
ignorefile: str = "ignore"
|
||||
settingsfile: str = "linkulatorrc"
|
||||
|
||||
|
||||
CONFIG = DefaultConfigOptions()
|
||||
CONFIG.all_homedir_pattern = "/home/*/"
|
||||
CONFIG.datadir = ".linkulator"
|
||||
CONFIG.datafile = "linkulator.data"
|
||||
CONFIG.ignorefile = "ignore"
|
||||
PATHS = DefaultPaths()
|
||||
|
||||
CONFIG.my_datadir = Path(Path.home() / CONFIG.datadir)
|
||||
CONFIG.my_datafile = Path(CONFIG.my_datadir / CONFIG.datafile)
|
||||
CONFIG.my_ignorefile = Path(CONFIG.my_datadir / CONFIG.ignorefile)
|
||||
|
||||
class DefaultUser(object):
|
||||
"""data class containing user defaults"""
|
||||
|
||||
datadir: Path = Path.home() / PATHS.datadir
|
||||
datafile: Path = datadir / PATHS.datafile
|
||||
ignorefile: Path = datadir / PATHS.ignorefile
|
||||
settingsfile: Path = datadir / PATHS.settingsfile
|
||||
lastlogin = time()
|
||||
browser: str = "lynx"
|
||||
|
||||
|
||||
USER = DefaultUser()
|
||||
|
||||
|
||||
def is_readable(st_mode: int) -> bool:
|
||||
"""Checks the provided mode is group and other readable, returns true if this is the case
|
||||
|
||||
Check if 700 is readable:
|
||||
>>> is_readable(16832)
|
||||
False
|
||||
|
||||
Check if 755 is readable:
|
||||
>>> is_readable(16877)
|
||||
True
|
||||
"""
|
||||
if bool(st_mode & stat.S_IRGRP) & bool(st_mode & stat.S_IROTH):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def init():
|
||||
"""Performs startup checks to ensure environment is set up for use
|
||||
|
||||
Creates necessary data directory and data file. If they exist, no error
|
||||
occurs.
|
||||
Checks that the data directory and data file are group and other readable.
|
||||
Sets some correct permissions if they are not.
|
||||
Other errors may raise an exception.
|
||||
"""
|
||||
|
||||
USER.datadir.mkdir(mode=0o755, exist_ok=True)
|
||||
|
||||
if not is_readable(USER.datadir.stat().st_mode):
|
||||
print(
|
||||
"Warning: %s is not group or other readable - changing permissions"
|
||||
% str(USER.datadir)
|
||||
)
|
||||
USER.datadir.chmod(0o755)
|
||||
|
||||
USER.datafile.touch(mode=0o644, exist_ok=True)
|
||||
|
||||
if not is_readable(USER.datafile.stat().st_mode):
|
||||
print(
|
||||
"Warning: %s is not group or other readable - changing permissions"
|
||||
% str(USER.datafile)
|
||||
)
|
||||
USER.datafile.chmod(0o644)
|
||||
|
||||
try:
|
||||
#TODO JSONDecodeError needs to be handled
|
||||
with open(USER.settingsfile) as file:
|
||||
l = json.load(file)
|
||||
USER.lastlogin = l["lastlogin"]
|
||||
USER.browser = l["browser"]
|
||||
except FileNotFoundError:
|
||||
with open(USER.settingsfile, 'w') as file:
|
||||
json.dump({"lastlogin": USER.lastlogin, "browser": USER.browser}, file)
|
||||
|
||||
|
||||
def save():
|
||||
with open(USER.settingsfile, 'w') as file:
|
||||
USER.lastlogin = str(time())
|
||||
json.dump({"lastlogin": USER.lastlogin, "browser": USER.browser}, file)
|
||||
|
|
77
linkulator
77
linkulator
|
@ -5,7 +5,6 @@
|
|||
import getpass
|
||||
import os
|
||||
import signal
|
||||
import stat
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
@ -14,13 +13,11 @@ from glob import glob
|
|||
from pathlib import Path, PurePath
|
||||
from shutil import which
|
||||
|
||||
import config
|
||||
import posts
|
||||
from config import CONFIG as config
|
||||
|
||||
username = getpass.getuser()
|
||||
|
||||
browser = "lynx"
|
||||
|
||||
help_text = """
|
||||
options: -h or --help; -p or --post; or no option to browse links.
|
||||
|
||||
|
@ -55,8 +52,8 @@ ignore_names = []
|
|||
# IGNORE NAMES.
|
||||
def parse_ignore_file():
|
||||
global ignore_names
|
||||
if config.my_ignorefile.exists():
|
||||
s = config.my_ignorefile.read_text()
|
||||
if config.USER.ignorefile.exists():
|
||||
s = config.USER.ignorefile.read_text()
|
||||
l = s.splitlines()
|
||||
for line in l:
|
||||
name = line.split(" ")[0]
|
||||
|
@ -68,7 +65,9 @@ def build_menu():
|
|||
## DISK IO IS PROBABLY THE HEAVIEST PART OF THIS SCRIPT, DON'T DO THIS OFTEN.
|
||||
|
||||
files_pattern = str(
|
||||
PurePath(config.all_homedir_pattern).joinpath(config.datadir, config.datafile)
|
||||
PurePath(config.PATHS.all_homedir_pattern).joinpath(
|
||||
config.PATHS.datadir, config.PATHS.datafile
|
||||
)
|
||||
)
|
||||
linkulator_files = glob(files_pattern)
|
||||
|
||||
|
@ -223,7 +222,7 @@ def view_thread(post_id):
|
|||
next_text = "\nType {} to reply, {} to view in {}, {} for main menu, or {} to quit: ".format(
|
||||
style_text("r", "underline"),
|
||||
style_text("b", "underline"),
|
||||
browser,
|
||||
config.USER.browser,
|
||||
style_text("m", "underline"),
|
||||
style_text("q", "underline"),
|
||||
)
|
||||
|
@ -246,10 +245,10 @@ def view_thread(post_id):
|
|||
|
||||
|
||||
def view_link_in_browser(url, post_id):
|
||||
if which(browser) is None:
|
||||
if which(config.USER.browser) is None:
|
||||
print(
|
||||
"Sorry, "
|
||||
+ browser
|
||||
+ config.USER.browser
|
||||
+ " is not installed on your system. Ask your sysadmin to install it."
|
||||
)
|
||||
view_thread(post_id)
|
||||
|
@ -259,12 +258,12 @@ def view_link_in_browser(url, post_id):
|
|||
or url.startswith("https://")
|
||||
or url.startswith("http://")
|
||||
):
|
||||
subprocess.call(["lynx", url])
|
||||
subprocess.call([config.USER.browser, url])
|
||||
else:
|
||||
print("Sorry, that url doesn't start with gopher://, http:// or https://")
|
||||
tryAnyway = input("Do you want to try it in", browser, "anyway? Y/[N] ")
|
||||
tryAnyway = input("Do you want to try it in", config.USER.browser, "anyway? Y/[N] ")
|
||||
if tryAnyway == "Y" or tryAnyway == "y":
|
||||
subprocess.call(["lynx", url])
|
||||
subprocess.call([config.USER.browser, url])
|
||||
view_thread(post_id)
|
||||
|
||||
|
||||
|
@ -273,11 +272,11 @@ def reply(owner, tstamp, post_id):
|
|||
|
||||
comment = input("Enter your comment: ")
|
||||
|
||||
if os.path.exists(config.my_datafile):
|
||||
if os.path.exists(config.USER.datafile):
|
||||
append_write = "a" # append if already exists
|
||||
else:
|
||||
append_write = "w+" # make a new file if not
|
||||
with open(config.my_datafile, append_write) as file:
|
||||
with open(config.USER.datafile, append_write) as file:
|
||||
timestamp = str(time.time())
|
||||
file.write(timestamp + "|" + owner + "+" + tstamp + "|||" + comment + "\r")
|
||||
|
||||
|
@ -307,53 +306,9 @@ def search(keyword):
|
|||
## if next_step...
|
||||
|
||||
|
||||
def is_readable(st_mode: int) -> bool:
|
||||
"""Checks the provided mode is group and other readable, returns true if this is the case
|
||||
|
||||
Check if 700 is readable:
|
||||
>>> is_readable(16832)
|
||||
False
|
||||
|
||||
Check if 755 is readable:
|
||||
>>> is_readable(16877)
|
||||
True
|
||||
"""
|
||||
if bool(st_mode & stat.S_IRGRP) & bool(st_mode & stat.S_IROTH):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def init():
|
||||
"""Performs startup checks to ensure environment is set up for use
|
||||
|
||||
Creates necessary data directory and data file. If they exist, no error
|
||||
occurs.
|
||||
Checks that the data directory and data file are group and other readable.
|
||||
Sets some correct permissions if they are not.
|
||||
Other errors may raise an exception.
|
||||
"""
|
||||
dir_p = Path(Path.home(), ".linkulator")
|
||||
file_p = Path(dir_p, "linkulator.data")
|
||||
|
||||
dir_p.mkdir(mode=0o755, exist_ok=True)
|
||||
file_p.touch(mode=0o644, exist_ok=True)
|
||||
|
||||
if not is_readable(dir_p.stat().st_mode):
|
||||
print(
|
||||
"Warning: %s is not group or other readable - changing permissions"
|
||||
% str(dir_p)
|
||||
)
|
||||
dir_p.chmod(0o755)
|
||||
if not is_readable(file_p.stat().st_mode):
|
||||
print(
|
||||
"Warning: %s is not group or other readable - changing permissions"
|
||||
% str(file_p)
|
||||
)
|
||||
file_p.chmod(0o644)
|
||||
|
||||
|
||||
def graceful_exit():
|
||||
print("\n\nThank you for linkulating. Goodbye.\n")
|
||||
config.save()
|
||||
exit(0)
|
||||
|
||||
|
||||
|
@ -366,7 +321,7 @@ signal.signal(signal.SIGINT, signal_handler)
|
|||
|
||||
def parse_command():
|
||||
args = sys.argv[1:]
|
||||
init()
|
||||
config.init()
|
||||
if not len(args):
|
||||
print(" ----------")
|
||||
print(" LINKULATOR")
|
||||
|
|
6
posts.py
6
posts.py
|
@ -6,7 +6,7 @@ import readline
|
|||
import sys
|
||||
import time
|
||||
|
||||
from config import CONFIG as config
|
||||
import config
|
||||
|
||||
USERNAME = getpass.getuser()
|
||||
|
||||
|
@ -57,11 +57,11 @@ def get_input(item: str, prefill) -> str:
|
|||
|
||||
def save_link(link) -> None:
|
||||
"""Saves the specified link data to the user's data file"""
|
||||
if os.path.exists(config.my_datafile):
|
||||
if os.path.exists(config.USER.datafile):
|
||||
append_write = "a" # append if already exists
|
||||
else:
|
||||
append_write = "w+" # make a new file if not
|
||||
with open(config.my_datafile, append_write) as file:
|
||||
with open(config.USER.datafile, append_write) as file:
|
||||
file.write(
|
||||
link.timestamp
|
||||
+ "||"
|
||||
|
|
Loading…
Reference in New Issue
Block a user