1919from sphinxcontrib .confluencebuilder .config .checks import validate_configuration
2020from sphinxcontrib .confluencebuilder .config .defaults import apply_defaults
2121from sphinxcontrib .confluencebuilder .config .env import apply_env_overrides
22+ from sphinxcontrib .confluencebuilder .config .env import build_hash
23+ from sphinxcontrib .confluencebuilder .env import ConfluenceCacheInfo
2224from sphinxcontrib .confluencebuilder .intersphinx import build_intersphinx
2325from sphinxcontrib .confluencebuilder .logger import ConfluenceLogger
2426from sphinxcontrib .confluencebuilder .nodes import confluence_footer
@@ -67,12 +69,15 @@ def __init__(self, app, env=None):
6769 self .domain_indices = {}
6870 self .file_suffix = '.conf'
6971 self .info = ConfluenceLogger .info
72+ self .legacy_assets = {}
73+ self .legacy_pages = None
7074 self .link_suffix = None
7175 self .metadata = defaultdict (dict )
7276 self .nav_next = {}
7377 self .nav_prev = {}
7478 self .omitted_docnames = []
7579 self .orphan_docnames = []
80+ self .parent_id = None
7681 self .publish_allowlist = None
7782 self .publish_denylist = None
7883 self .publish_docnames = []
@@ -84,8 +89,10 @@ def __init__(self, app, env=None):
8489 self .use_search = None
8590 self .verbose = ConfluenceLogger .verbose
8691 self .warn = ConfluenceLogger .warn
92+ self ._cache_info = ConfluenceCacheInfo (self )
8793 self ._cached_footer_data = None
8894 self ._cached_header_data = None
95+ self ._config_confluence_hash = None
8996 self ._original_get_doctree = None
9097 self ._verbose = self .app .verbosity
9198
@@ -148,6 +155,14 @@ def init(self):
148155 self .config .sphinx_verbosity = self ._verbose
149156 self .publisher .init (self .config , self .cloud )
150157
158+ # With the configuration finalizes, generate a Confluence-specific
159+ # configuration hash that is applicable to this run
160+ self ._config_confluence_hash = build_hash (config )
161+ self .verbose ('configuration hash ' + self ._config_confluence_hash )
162+
163+ self ._cache_info .load_cache ()
164+ self ._cache_info .configure (self ._config_confluence_hash )
165+
151166 self .create_template_bridge ()
152167 self .templates .init (self )
153168
@@ -209,27 +224,11 @@ def get_outdated_docs(self):
209224 """
210225 Return an iterable of input files that are outdated.
211226 """
212- # This method is taken from TextBuilder.get_outdated_docs()
213- # with minor changes to support :confval:`rst_file_transform`.
227+
214228 for docname in self .env .found_docs :
215- if docname not in self .env . all_docs :
229+ if self ._cache_info . is_outdated ( docname ) :
216230 yield docname
217231 continue
218- sourcename = path .join (self .env .srcdir , docname +
219- self .file_suffix )
220- targetname = path .join (self .outdir , self .file_transform (docname ))
221-
222- try :
223- targetmtime = path .getmtime (targetname )
224- except Exception :
225- targetmtime = 0
226- try :
227- srcmtime = path .getmtime (sourcename )
228- if srcmtime > targetmtime :
229- yield docname
230- except OSError :
231- # source doesn't exist anymore
232- pass
233232
234233 def get_target_uri (self , docname , typ = None ):
235234 return self .link_transform (docname )
@@ -483,6 +482,8 @@ def write_doc(self, docname, doctree):
483482 except OSError as err :
484483 self .warn (f'error writing file { outfilename } : { err } ' )
485484
485+ self ._cache_info .track_page_hash (docname )
486+
486487 def publish_doc (self , docname , output ):
487488 conf = self .config
488489 title = self .state .title (docname )
@@ -519,6 +520,8 @@ def publish_doc(self, docname, output):
519520 uploaded_id = self .publisher .store_page (title , data , parent_id )
520521 self .state .register_upload_id (docname , uploaded_id )
521522
523+ self ._cache_info .track_last_page_id (docname , uploaded_id )
524+
522525 if self .config .root_doc == docname :
523526 self .root_doc_page_id = uploaded_id
524527
@@ -751,8 +754,6 @@ def finish(self):
751754
752755 # publish generated output (if desired)
753756 if self .publish :
754- self .legacy_assets = {}
755- self .legacy_pages = None
756757 self .parent_id = self .publisher .get_base_page_id ()
757758
758759 for docname in status_iterator (
@@ -802,9 +803,21 @@ def to_asset_name(asset):
802803 except OSError as err :
803804 self .warn (f'error reading asset { key } : { err } ' )
804805
806+ # if we have documents that were not changes (and therefore, not
807+ # needing to be republished), assume any cached publish page ids
808+ # are still valid and remove them from the legacy pages list
809+ other_docs = self .env .all_docs .keys () - set (self .publish_docnames )
810+ for unchanged_doc in other_docs :
811+ lpid = self ._cache_info .last_page_id (unchanged_doc )
812+ if lpid is not None and lpid in self .legacy_pages :
813+ self .legacy_pages .remove (lpid )
814+
805815 self .publish_cleanup ()
806816 self .publish_finalize ()
807817
818+ # persist cache from this run
819+ self ._cache_info .save_cache ()
820+
808821 def cleanup (self ):
809822 if self .publish :
810823 self .publisher .disconnect ()
0 commit comments