diff --git a/Source/Build.py b/Source/Build.py index 1cdfb35..df7cb69 100755 --- a/Source/Build.py +++ b/Source/Build.py @@ -19,7 +19,7 @@ try: from Modules.ActivityPub import * ActivityPub = True except: - print("[E] Can't load the ActivityPub module. Its use is disabled. Make sure the 'requests' library is installed.") + print("[W] ⚠️ Can't load the ActivityPub module. Its use is disabled. Make sure the 'requests' library is installed.") ActivityPub = False from Modules.Config import * @@ -29,18 +29,18 @@ from Modules.Site import * from Modules.Sitemap import * from Modules.Utils import * -def ResetPublic(OutputDir): - for i in (OutputDir, f"{OutputDir}.gmi"): +def ResetOutputDir(OutDir): + for e in (OutDir, f"{OutDir}.gmi"): try: - shutil.rmtree(i) + shutil.rmtree(e) except FileNotFoundError: pass -def DelTmp(OutputDir): +def DelTmp(OutDir): for Ext in FileExtensions['Tmp']: - for File in Path(OutputDir).rglob(f"*.{Ext}"): + for File in Path(OutDir).rglob(f"*.{Ext}"): os.remove(File) - for Dir in (OutputDir, f"{OutputDir}.gmi"): + for Dir in (OutDir, f"{OutDir}.gmi"): for File in Path(Dir).rglob('*.tmp'): os.remove(File) @@ -73,16 +73,48 @@ def CheckSafeOutputDir(OutDir): OutDir = os.path.realpath(OutDir) OutFolder = OutDir.split('/')[-1] if InDir == OutDir: - print(f"[E] Output and Input directories ({OutDir}) can't be the same. Exiting.") + print(f"[E] ⛔ Output and Input directories ({OutDir}) can't be the same. Exiting.") exit(1) elif OutFolder in ReservedPaths and f"{InDir}/{OutFolder}" == OutDir: - print(f"[E] Output directory {OutDir} can't be a reserved subdirectory of the Input. Exiting.") + print(f"[E] ⛔ Output directory {OutDir} can't be a reserved subdirectory of the Input. Exiting.") exit(1) +def GetModifiedFiles(OutDir): + All, Mod = [], [] + for Path in ('Pages', 'Posts'): + for Root, Dirs, Files in os.walk(Path): + for File in Files: + Src = os.path.join(Root,File) + SrcTime = int(os.path.getmtime(Src)) + if Path == 'Pages': + Tmp = '/'.join(Src.split('/')[1:]) + elif Path == 'Posts': + Tmp = Src + Obj = f"{OutDir}/{StripExt(Tmp)}.html" + try: + ObjTime = int(os.path.getmtime(Obj)) + except FileNotFoundError: + ObjTime = 0 + All += [{'Tmp':Tmp, 'SrcTime':SrcTime, 'ObjTime':ObjTime}] + for File in All: + if File['SrcTime'] > File['ObjTime']: + Mod += [File['Tmp']] + #Latest = 0 + #for File in Sources: + # if File['t'] > Latest: + # Latest = File['t'] + #Meta = ReadFile('staticoso.meta') + return Mod + def Main(Args, FeedEntries): HavePages, HavePosts = False, False SiteConf = LoadConfFile('Site.ini') + #if Args.InputDir: + # os.chdir(Args.InputDir) + # print(f"[I] Current directory: {Args.InputDir}") + + CleanBuild = Args.CleanBuild OutputDir = Args.OutputDir if Args.OutputDir else ReadConf(SiteConf, 'Site', 'OutputDir') if ReadConf(SiteConf, 'Site', 'OutputDir') else 'public' OutputDir = OutputDir.removesuffix('/') CheckSafeOutputDir(OutputDir) @@ -120,18 +152,23 @@ def Main(Args, FeedEntries): else: ConfMenu = [] - ResetPublic(OutputDir) + if CleanBuild: + print("[I] Building Clean") + ResetOutputDir(OutputDir) + else: + print("[I] Building Differentially") + LimitFiles = GetModifiedFiles(OutputDir) if os.path.isdir('Pages'): HavePages = True - shutil.copytree('Pages', OutputDir) + shutil.copytree('Pages', OutputDir, dirs_exist_ok=True) if GemtextOut: - shutil.copytree('Pages', f"{OutputDir}.gmi", ignore=IgnoreFiles) + shutil.copytree('Pages', f"{OutputDir}.gmi", ignore=IgnoreFiles, dirs_exist_ok=True) if os.path.isdir('Posts'): HavePosts = True - shutil.copytree('Posts', f"{OutputDir}/Posts") + shutil.copytree('Posts', f"{OutputDir}/Posts", dirs_exist_ok=True) if GemtextOut: - shutil.copytree('Posts', f"{OutputDir}.gmi/Posts", ignore=IgnoreFiles) + shutil.copytree('Posts', f"{OutputDir}.gmi/Posts", ignore=IgnoreFiles, dirs_exist_ok=True) if not (HavePages or HavePosts): print("[E] No Pages or posts found. Nothing to do, exiting!") @@ -140,6 +177,7 @@ def Main(Args, FeedEntries): print("[I] Generating HTML") Pages = MakeSite( OutputDir=OutputDir, + LimitFiles=LimitFiles, TemplatesText=LoadFromDir('Templates', ['*.htm', '*.html']), StaticPartsText=LoadFromDir('StaticParts', ['*.htm', '*.html']), DynamicParts=DynamicParts, @@ -220,11 +258,14 @@ def Main(Args, FeedEntries): print("[I] Copying Assets") os.system(f"cp -R Assets/* {OutputDir}/") - print("[I] Done!") + print("[I] ✅ Done!") if __name__ == '__main__': Parser = argparse.ArgumentParser() + Parser.add_argument('--CleanBuild', action='store_true') Parser.add_argument('--OutputDir', type=str) + #Parser.add_argument('--InputDir', type=str) + #Parser.add_argument('--InputFiles', type=str, nargs='+') Parser.add_argument('--Sorting', type=str) Parser.add_argument('--SiteLang', type=str) Parser.add_argument('--SiteRoot', type=str) @@ -257,7 +298,7 @@ if __name__ == '__main__': from Modules.Feed import * FeedEntries = Args.FeedEntries if Args.FeedEntries else 'Default' except: - print("[W] Can't load the XML libraries. XML Feeds Generation is Disabled. Make sure the 'lxml' library is installed.") + print("[W] ⚠️ Can't load the XML libraries. XML Feeds Generation is Disabled. Make sure the 'lxml' library is installed.") FeedEntries = 0 Main( diff --git a/Source/Modules/Config.py b/Source/Modules/Config.py index 5b9b849..984a9b2 100644 --- a/Source/Modules/Config.py +++ b/Source/Modules/Config.py @@ -7,7 +7,6 @@ | Copyright (C) 2022, OctoSpacc | | ================================= """ -import io import configparser from ast import literal_eval diff --git a/Source/Modules/Pug.py b/Source/Modules/Pug.py index 4cccc6c..f2fa868 100644 --- a/Source/Modules/Pug.py +++ b/Source/Modules/Pug.py @@ -12,11 +12,11 @@ import os from Modules.Utils import * -def PugCompileList(OutputDir, Pages): +def PugCompileList(OutputDir, Pages, LimitFiles): # Pug-cli seems to shit itself with folder paths as input, so we pass ALL the files as arguments Paths = '' for File, Content, Titles, Meta in Pages: - if File.lower().endswith('.pug'): + if File.lower().endswith('.pug') and File in LimitFiles: Path = f'{OutputDir}/{File}' WriteFile(Path, Content) Paths += f'"{Path}" ' diff --git a/Source/Modules/Site.py b/Source/Modules/Site.py index 3fe7e6c..94d8410 100644 --- a/Source/Modules/Site.py +++ b/Source/Modules/Site.py @@ -373,7 +373,7 @@ def DoMinifyHTML(HTML): convert_charrefs=True, keep_pre=True) -def MakeSite(OutputDir, TemplatesText, StaticPartsText, DynamicParts, DynamicPartsText, ConfMenu, GlobalMacros, SiteName, BlogName, SiteTagline, SiteTemplate, SiteDomain, SiteRoot, FolderRoots, SiteLang, Locale, Minify, NoScripts, ImgAltToTitle, ImgTitleToAlt, Sorting, MarkdownExts, AutoCategories): +def MakeSite(OutputDir, LimitFiles, TemplatesText, StaticPartsText, DynamicParts, DynamicPartsText, ConfMenu, GlobalMacros, SiteName, BlogName, SiteTagline, SiteTemplate, SiteDomain, SiteRoot, FolderRoots, SiteLang, Locale, Minify, NoScripts, ImgAltToTitle, ImgTitleToAlt, Sorting, MarkdownExts, AutoCategories): PagesPaths, PostsPaths, Pages, MadePages, Categories = [], [], [], [], {} for Ext in FileExtensions['Pages']: for File in Path('Pages').rglob(f"*.{Ext}"): @@ -381,14 +381,12 @@ def MakeSite(OutputDir, TemplatesText, StaticPartsText, DynamicParts, DynamicPar for File in Path('Posts').rglob(f"*.{Ext}"): PostsPaths += [FileToStr(File, 'Posts/')] - if PagesPaths: - PagesPaths = FileNameDateSort(PagesPaths) - if Sorting['Pages'] == 'Inverse': - PagesPaths.reverse() - if PostsPaths: - PostsPaths = FileNameDateSort(PostsPaths) - if Sorting['Posts'] == 'Inverse': - PostsPaths.reverse() + PagesPaths = FileNameDateSort(PagesPaths) + if Sorting['Pages'] == 'Inverse': + PagesPaths.reverse() + PostsPaths = FileNameDateSort(PostsPaths) + if Sorting['Posts'] == 'Inverse': + PostsPaths.reverse() print("[I] Preprocessing Source Pages") for Type in ['Page', 'Post']: @@ -403,7 +401,7 @@ def MakeSite(OutputDir, TemplatesText, StaticPartsText, DynamicParts, DynamicPar Pages += [[File, Content, Titles, Meta]] for Cat in Meta['Categories']: Categories.update({Cat:''}) - PugCompileList(OutputDir, Pages) + PugCompileList(OutputDir, Pages, LimitFiles) if Categories: print("[I] Generating Category Lists") diff --git a/Source/Modules/Utils.py b/Source/Modules/Utils.py index 52ddfff..10b2530 100644 --- a/Source/Modules/Utils.py +++ b/Source/Modules/Utils.py @@ -116,19 +116,20 @@ def RevSort(List): def FileNameDateSort(Old): # TODO: Test this for files not starting with date, and dated folders New = [] - Old.sort() - New.insert(0, Old[0]) - for i,e in enumerate(Old): - if i == 0: - continue - Done = False - for j,f in enumerate(New): - if NumsFromFileName(e) != e and NumsFromFileName(f) != f and NumsFromFileName(e) < NumsFromFileName(f): - New.insert(j, e) - Done = True - break - if not Done: - New += [e] + if Old: + Old.sort() + New.insert(0, Old[0]) + for i,e in enumerate(Old): + if i == 0: + continue + Done = False + for j,f in enumerate(New): + if NumsFromFileName(e) != e and NumsFromFileName(f) != f and NumsFromFileName(e) < NumsFromFileName(f): + New.insert(j, e) + Done = True + break + if not Done: + New += [e] return New def FirstRealItem(List): diff --git a/TODO b/TODO index cd82e77..6abbb5a 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,4 @@ +- Check if external tools are installed - Specify input folder(s) and files (idea is Makefile compatibility too) - Show page size/words/time in meta line - Add feed support for diary-like pages