[1.9.13]: see changelog

This commit is contained in:
Cyrille L 2023-10-01 01:47:27 +02:00
parent fed0227968
commit 171de8808c
15 changed files with 164 additions and 114 deletions

View File

@ -9,6 +9,12 @@ Tyto - Littérateur
# CURRENTLY IN DEV ! # CURRENTLY IN DEV !
## [1.9.13]
- Check: One-Line needed tags, titles
- Added first stats
- move ini template from tyto to domain for domain config file
- Check valid date in article and form domain date
## [1.9.12] ## [1.9.12]
- preparing check process : head tags in article - preparing check process : head tags in article

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Version: 1.9.12 # Version: 1.9.13
# Updated: 2023-09-30 1696082419 # Updated: 2023-10-01 1696117427
# Tyto - Littérateur # Tyto - Littérateur
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org> # Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>

View File

@ -33,6 +33,8 @@
#-------------------------- #--------------------------
import sys import sys
from dateutil.parser import parse
import args, domain, langs, debug, post, tools import args, domain, langs, debug, post, tools
@ -61,8 +63,7 @@ def manage(action, target):
# target is not "all" # target is not "all"
ready() ready()
if target.endswith(".tyto"): target.endswith(".tyto") and is_article(target)
is_article(target)
#================================# #================================#
@ -70,29 +71,24 @@ def manage(action, target):
# Also used with multiple (loop) # # Also used with multiple (loop) #
#--------------------------------# #--------------------------------#
def is_article(target): def is_article(target):
if not post.is_article(target): valid(target)
if args.multiple:
return # Let other articles pass
sys.exit(post.error)
validators()
if post.error != 0:
if args.targets:
return # Let other articles pass
sys.exit(post.error)
print("pass", post.error, args.multiple)
print("pass", post.error, args.targets)
print("chk_date", chk_date)
print("post.stats_comments =", post.stats_comments)
# #
# #
# #
def validators(): def valid(target):
targets = args.targets targets = args.targets
# Target is a tyto article
post.is_article(target) or tools.exit(targets, post.error)
# One Line targs in head_contents
post.error == 0 and ol_tags() or tools.exit(targets, post.error) post.error == 0 and ol_tags() or tools.exit(targets, post.error)
post.error == 0 and titles() or tools.exit(targets, post.error)
#===========================================# #===========================================#
@ -102,10 +98,16 @@ def multiple_targets():
ready() ready()
#=======================# #==============#
# check header contents # # check header #===============================================================
#-----------------------# #==============#
#======================#
# One Line needed tags #
#----------------------#
def ol_tags(): def ol_tags():
global sitemap
sitemap = "True"
for ln, line in enumerate(post.head_contents.rsplit("\n"), 1): for ln, line in enumerate(post.head_contents.rsplit("\n"), 1):
if not line or line.isspace() or line.startswith("#"): continue if not line or line.isspace() or line.startswith("#"): continue
@ -125,15 +127,22 @@ def ol_tags():
elif not post.tags[1] and line.startswith(post.tags[0]): elif not post.tags[1] and line.startswith(post.tags[0]):
post.tags = (post.tags[0], ol_tag_value(line, True)) post.tags = (post.tags[0], ol_tag_value(line, True))
elif line.startswith(post.nositemap):
sitemap = "False"
# Sets are done from loop # Sets are done from loop
# Check if tag value exists # Check if tag value exists
# ========================= # =========================
if not is_ol_tag(post.title[0], post.title[1]): return if not is_ol_tag(post.date[0], post.date[1]): return False
if not is_ol_tag(post.about[0], post.about[1]): return if not is_valid_date(post.date[1]): return False
if not is_ol_tag(post.date[0], post.date[1]): return if not is_ol_tag(post.title[0], post.title[1]): return False
if not is_ol_tag(post.author[0], post.author[1]): return if not is_ol_tag(post.about[0], post.about[1]): return False
if not is_ol_tag(post.tags[0], post.tags[1]): return if not is_ol_tag(post.author[0], post.author[1]): return False
if not is_ol_tag(post.tags[0], post.tags[1]): return False
return True
#===========================================# #===========================================#
@ -144,7 +153,7 @@ def ol_tags():
def ol_tag_value(line, commas): def ol_tag_value(line, commas):
value = line.rsplit(":")[1].lstrip() value = line.rsplit(":")[1].lstrip()
# reformat comma separated items, removing first space # reformat comma separated items, removing first spaces
if commas: if commas:
tuple_values = value.rsplit(",") tuple_values = value.rsplit(",")
value = "" value = ""
@ -162,15 +171,57 @@ def ol_tag_value(line, commas):
#---------------------------# #---------------------------#
def is_ol_tag(tag, value): def is_ol_tag(tag, value):
if not value: if not value:
post.error = 51 post.error = debug.out(51, "%s ?"%tag, post.uri, True, 2, False)
debug.out(51, "%s ?"%tag, post.uri, True, 2, False)
return False return False
return True return True
# #======================================#
# # Check validity date #
# # set date of check (YYYY-MM-DD H:M:S) #
def valid_date(): # Also set epoch date #
# Return True/False #
#--------------------------------------#
def is_valid_date(date):
global chk_date
try:
parse(date)
chk_date = tools.nowdate()
return True
except:
post.error = debug.out(50, "%s"%date, post.uri, True, 2, False)
return False
#===============#
# check article #==============================================================
#===============#
#============================#
# Check optional title tags #
# Count tyto + html comments #
# Return True/False #
#----------------------------#
def titles():
for ln, line in enumerate(post.text_contents.rsplit("\n"),
post.head_lines + 1):
if not line or line.isspace():
continue
if line.startswith(post.tyto_titles):
if not line[3:]:
post.error = \
debug.out(52, "%s. %s ?"%(ln, line), post.uri, True, 2, False)
return False
post.stats_titles += 1
elif line[1].isdigit() and int(line[1]) >= 6:
post.error = \
debug.out(52, "%s) %s..."%(ln, line[0:10]), post.uri, True, 1, False)
return False
elif line.startswith(post.text_comments):
post.stats_comments += 1
return True

View File

@ -49,10 +49,11 @@ import langs, args
def out(nbr, var, val, show, color, stop): def out(nbr, var, val, show, color, stop):
args.get_options() args.get_options()
if not show: if not show:
show = args.dlogs or args.erron and color > 0 # Show only warn and error logs # Show only warn and error logs
show = args.dlogs or args.erron and color > 0
if not show: if not show:
return return nbr
# COlors # COlors
CS = '\033[0;0m' # Unset CS = '\033[0;0m' # Unset
@ -89,6 +90,7 @@ def out(nbr, var, val, show, color, stop):
23 : langs.logs.err_post_empty, 23 : langs.logs.err_post_empty,
50 : langs.logs.err_date, 50 : langs.logs.err_date,
51 : langs.logs.err_post_data, 51 : langs.logs.err_post_data,
52 : langs.logs.err_post_title,
# WARNINGS (100-200) # WARNINGS (100-200)
100 : langs.logs.warn_no_dom, 100 : langs.logs.warn_no_dom,
101 : langs.logs.domain_created, 101 : langs.logs.domain_created,
@ -126,4 +128,6 @@ def out(nbr, var, val, show, color, stop):
if nbr >= 200: if nbr >= 200:
nbr = 0 nbr = 0
sys.exit(nbr) sys.exit(nbr)
return nbr

View File

@ -32,7 +32,9 @@
# file program : # file program :
#-------------------------- #--------------------------
import os, re, configparser import os, re
from dateutil.parser import parse
import debug, domain, langs, tools import debug, domain, langs, tools
@ -53,11 +55,8 @@ def ask(q, yes_only, default):
if yes_only: if yes_only:
expected = langs.logs.ok expected = langs.logs.ok
try: try: answer = input(q)
answer = input(q) except KeyboardInterrupt: print("") ; maybe_later(expected, "?")
except KeyboardInterrupt:
print("")
maybe_later(expected, "?")
# return default answer if exists # return default answer if exists
if not answer: if not answer:
@ -71,6 +70,7 @@ def ask(q, yes_only, default):
for ok in langs.logs.ok: for ok in langs.logs.ok:
if answer.lower() == ok.lower(): if answer.lower() == ok.lower():
return True return True
maybe_later(expected, answer) maybe_later(expected, answer)
return answer return answer
@ -123,30 +123,21 @@ def ask_domain_title(update):
#---------------------------# #---------------------------#
def ask_domain_date(update): def ask_domain_date(update):
try: date = domain.cf.get("DOMAIN", "date") try: date = domain.cf.get("DOMAIN", "date")
except: date = "YYYY[-MM-DD]" except: date = "YYYY[-MM][-DD]"
example = date or "YYYY[-MM-DD]" example = date
q = "> %s (%s)%s "%(langs.logs.domain_date, example, langs.logs.q) q = "> %s (%s)%s "%(langs.logs.domain_date, example, langs.logs.q)
answer = ask(q, False, date) answer = ask(q, False, date)
# Check date format (not valid date) # Check date format (not valid date)
test = True try:
tuple_date = answer.rsplit("-") parse(answer)
tuple_len = len(tuple_date) except:
for i in range(tuple_len): debug.out(50, "YYYY[-MM-DD]", answer, True, 2, False)
if i == 0: ask_domain_date(update)
if len(tuple_date[i]) != 4 or not tuple_date[i].isdigit(): return
test = False
break
elif len(tuple_date[i]) != 2 or not tuple_date[i].isdigit():
test = False
break
# Exit if not valid
if not test:
debug.out(50, "YYYY[-MM-DD]", answer, True, 2, True)
if update: tools.update_ini_file(domain.cf_uri, "DOMAIN", "date", answer) if update: tools.update_ini_file(domain.cf_uri, "DOMAIN", "date", answer)
else: return answer else: return answer

View File

@ -36,6 +36,9 @@ import os, configparser
import domain, debug, tools, tyto import domain, debug, tools, tyto
error = 0
#============================================# #============================================#
# Check if current directory is in articles/ # # Check if current directory is in articles/ #
# Check if article from target exists # # Check if article from target exists #
@ -47,20 +50,16 @@ def is_article(target):
domain.user_dir.startswith(domain.wrk_articles) or \ domain.user_dir.startswith(domain.wrk_articles) or \
debug.out(2, "-> articles/", domain.wrk_articles, True, 2, True) debug.out(2, "-> articles/", domain.wrk_articles, True, 2, True)
global error
# Target URI most be from legacy directory or not begins with # Target URI most be from legacy directory or not begins with
if target.startswith(tyto.notarget): if target.startswith(tyto.notarget):
debug.out(20, "./, ../", target, True, 2, False) error = debug.out(20, "./, ../", target, True, 2, False)
error = 20
return False return False
# Article exists # Article exists
global uri global uri
uri = os.path.join(domain.wrk_articles, target) uri = os.path.join(domain.wrk_articles, target)
if not os.path.exists(uri): if not os.path.exists(uri):
debug.out(5, "False", uri, True, 2, False) error = debug.out(5, "False", uri, True, 2, False)
error = 5
return False return False
# Article is a Tyto format and not empty (exit on errors) # Article is a Tyto format and not empty (exit on errors)
@ -89,18 +88,16 @@ def is_article(target):
# Return True or False # # Return True or False #
#-----------------------------------------# #-----------------------------------------#
def is_tyto_format(): def is_tyto_format():
global head_contents, text_contents, error global head_contents, text_contents
global head_lines, text_lines, lines
separator = False separator = False
head_contents = text_contents = "" head_contents = text_contents = ""
with open(uri, "r") as contents: with open(uri, "r") as contents:
contents = contents.read() contents = contents.read()
for line in contents.rsplit("\n"): for lines, line in enumerate(contents.rsplit("\n"), 1):
if not line: if line.startswith(sep):
continue
if line.startswith(post_sep):
separator = True separator = True
continue continue
@ -108,20 +105,20 @@ def is_tyto_format():
else: head_contents = "%s%s\n"%(head_contents, line) else: head_contents = "%s%s\n"%(head_contents, line)
if not separator: if not separator:
debug.out(21, post_sep, uri, True, 2, False) error = debug.out(21, sep, uri, True, 2, False)
error = 21
return False return False
if not head_contents: if not head_contents:
debug.out(22, "?", uri, True, 2, False) error = debug.out(22, "?", uri, True, 2, False)
error = 22
return False return False
if not text_contents: if not text_contents:
debug.out(23, "?", uri, True, 2, False) error = debug.out(23, "?", uri, True, 2, False)
error = 23
return False return False
head_lines = len(head_contents.rsplit("\n"))
text_lines = lines - head_lines
return True return True
@ -156,16 +153,41 @@ def cf_valid():
#======# #======#
# MAIN # # MAIN #=======================================================================
#======# #======#
error = 0
# Tag separator to split head and text article # head_contents
post_sep = "-----" #==============
# One Line Tags in head article # Optional Tags
nositemap = "! NoSitemap" # Article will not be included in sitemap
# One Line needed
sep = "-----" # Splitter between header and article
title = ("title:", False) title = ("title:", False)
about = ("about:", False) about = ("about:", False)
date = ("date:", False) date = ("date:", False)
tags = ("tags:", False) tags = ("tags:", False)
author = ("author:", False) author = ("author:", False)
# text_contents
# =============
# Comments
text_comments = (";;", "<!--")
html_comment = { text_comments[0] : "<!-- %s -->" }
# Tyto Titles #1 = <h2>
tyto_titles = ("#1", "#2", "#3", "#4", "#5")
html_titles = {
"#1" : '<h2 class="title_2">%s</h62>',
"#2" : '<h3 class="title_3">%s</h3>',
"#3" : '<h4 class="title_4">%s</h4>',
"#4" : '<h5 class="title_5">%s</h5>',
"#5" : '<h6 class="title_6">%s</h6>',
}
# Statistics
# ==========
stats_comments = 0
stats_titles = 0

View File

@ -48,35 +48,10 @@ def exit(targets, error):
#==============================# #==============================#
# Set and return date and time # # Set and return date and time #
# With local options from lang #
#------------------------------# #------------------------------#
def nowdate(spec): def nowdate():
# Default
F_Int = "'%Y-%m-%d %I:%M:%S %p'" # Full International date
S_Int = "'%Y-%m-%d" # Short International date
# Get spec option for local date
# Get Used domain lang and set format date
locales = ("FLocal", "SLocal")
if spec in locales:
domain.cf_load()
lang = domain.cf.get("WEBSITE", "lang")
if lang == "fr":
S_Int = "'%d/%m/%Y'"
F_Int = "'%d/%m/%Y %H:%M:%S'"
now = datetime.datetime.now() now = datetime.datetime.now()
setdate = { return(now.strftime('%Y-%m-%d %H:%M:%S'))
"FInt" : now.strftime(F_Int),
"SInt" : now.strftime(S_Int),
"FLocal" : now.strftime(F_Int),
"SLocal" : now.strftime(S_Int),
"Year" : now.strftime('%Y'),
"Epoch" : int(now.timestamp()),
}
return setdate[spec]
#========================# #========================#

View File

@ -49,7 +49,7 @@ domain_srv = "URI du serveur"
# Errors # Errors
err_arg = "Argument invalide" err_arg = "Argument invalide"
err_hole = "Dossier courant invalide" err_hole = "Dossier courant invalide"
err_date = "Format de date invalide" err_date = "Date invalide"
err_lang = "Format de langue invalide" err_lang = "Format de langue invalide"
err_dir = "Dossier non compatible" err_dir = "Dossier non compatible"
err_no_dir = "Dossier inexistant" err_no_dir = "Dossier inexistant"
@ -58,10 +58,11 @@ err_no_file = "Fichier manquant"
err_cr_file = "Fichier non créé" err_cr_file = "Fichier non créé"
err_bad_uri = "URI non compatible" err_bad_uri = "URI non compatible"
err_post_sep = "Séparateur manquant" err_post_sep = "Séparateur manquant"
err_post_head = "Erreur dans l'Entête" err_post_head = "Entête vide"
err_post_empty = "Article vide" err_post_empty = "Article vide"
err_ini_file = "Configuration invalide" err_ini_file = "Configuration invalide"
err_post_data = "Article: donnée manquante" err_post_data = "Donnée manquante"
err_post_title = "Titre invalide"
# Warnings # Warnings
warn_no_dom = "Domaine non configuré" warn_no_dom = "Domaine non configuré"