Implement JSDoc and embedding into our navbar without obvious CSS conflicts
[ndcode_site.git] / jsdoc / BuildCache.js.html
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4     <meta charset="utf-8">
5     <title>JSDoc: Source: BuildCache.js</title>
6
7     <script src="scripts/prettify/prettify.js"> </script>
8     <script src="scripts/prettify/lang-css.js"> </script>
9     <!--[if lt IE 9]>
10       <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
11     <![endif]-->
12     <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
13     <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
14 </head>
15
16 <body>
17
18 <div id="main">
19
20     <h1 class="page-title">Source: BuildCache.js</h1>
21
22     
23
24
25
26     
27     <section>
28         <article>
29             <pre class="prettyprint source linenums"><code>/*
30  * Copyright (C) 2018 Nick Downing &lt;nick@ndcode.org>
31  * SPDX-License-Identifier: MIT
32  *
33  * Permission is hereby granted, free of charge, to any person obtaining a copy
34  * of this software and associated documentation files (the "Software"), to
35  * deal in the Software without restriction, including without limitation the
36  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
37  * sell copies of the Software, and to permit persons to whom the Software is
38  * furnished to do so, subject to the following conditions:
39  *
40  * The above copyright notice and this permission notice shall be included in
41  * all copies or substantial portions of the Software.
42  *
43  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
45  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
46  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
47  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
48  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
49  * IN THE SOFTWARE.
50  */
51
52 let fs = require('fs')
53 let util = require('util')
54
55 let fs_stat = util.promisify(fs.stat)
56
57 /**
58  * Constructs a cache object. The cache object is intended to store objects of
59  * arbitrary JavaScript type, which are built from on-disk source files of some
60  * kind. The cache tracks the source files of each object, and makes sure the
61  * objects are rebuilt as required if the source files change on disk.
62  *
63  * @constructor
64  * @param {boolean} diag - Should diagnostic messages be printed to the
65  *   console.
66  */
67 let BuildCache = function(diag) {
68   if (!this instanceof BuildCache)
69     throw new Error('BuildCache is a constructor')
70   this.map = new Map()
71   this.diag = diag || false
72 }
73
74 /**
75  * Abstract method which is expected to build and return an object, given its
76  * key. Called from "get()" when the object does not exist or is out of date.
77  *
78  * If this method throws an exception, the key will be deleted from the cache
79  * and the exception re-thrown to the caller of "get()". If there are multiple
80  * callers to "get()" blocking and waiting for the build, they all receive the
81  * same exception object. So one has to be careful the exception is shareable.
82  *
83  * @method
84  * @param {string} key - Usually the path to the main source file on disk.
85  * @param {object} result - A dictionary to receive information about the built
86  *   object, you can optionally set "result.deps" to a list of dependency files
87  *   whose modification would invalidate the just-built and cached object.
88  */
89 BuildCache.prototype.build = async function(key, result) {
90   throw new Error('not implemented')
91 }
92
93 /**
94  * Retrieves the object stored in the cache under "key". If "key" already
95  * exists in the cache, then it will be checked for up-to-dateness. If present
96  * and up-to-date then its object is returned directly. Otherwise the abstract
97  * "build()" method is called to attempt to build the object, and either an
98  * exception is thrown or the built object is stored and return to the caller.
99  *
100  * Other callers requsting the same object while the original build progresses
101  * will be blocked, and all will wait for the build to complete. In this time,
102  * no new up-to-date check will be initiated. But as soon as the build is
103  * completed and the cache updated, further up-to-date checks become possible.
104  *
105  * An interesting alternate usage is provided for objects whose contents only
106  * matter if they have been rebuilt since last time. For example, suppose we
107  * want to periodically read a configuration file, and then possibly restart
108  * some long-running process if the configuration has changed. Then it is not
109  * necessary to store the result of configuration parsing in the cache, since
110  * it is only needed momentarily (while we're actually restarting the process).
111  * In such case, pass "once = true" and an "undefined" return means no change.
112  *
113  * @method
114  * @param {string} key - Usually the path to the main source file on disk.
115  * @param {boolean} once - If "true", it means the returned object will only be
116  *   used once. See above for a more comprehensive discussion of this feature.
117  */
118 BuildCache.prototype.get = async function(key, once) {
119   let result = this.map.get(key)
120   if (result === undefined) {
121     if (this.diag)
122       console.log(`building ${key}`)
123     result = {deps: [key], time: Date.now()}
124     result.done = this.build(key, result)
125     this.map.set(key, result)
126     try {
127       await result.done
128     }
129     catch (err) {
130       delete result.done
131       this.map.delete(key)
132       throw err
133     }
134     delete result.done
135   }
136   else if (result.done === undefined) {
137     if (this.diag)
138       console.log(`checking ${key}`)
139     result.done = (
140       async () => {
141         for (let i = 0; i &lt; result.deps.length; ++i) {
142           let stats
143           try {
144             stats = await fs_stat(result.deps[i])
145           }
146           catch (err) {
147             if (!(err instanceof Error) || err.code !== 'ENOENT')
148               throw err
149             //stats = undefined
150           }
151           if (stats === undefined || stats.mtimeMs > result.time) {
152             if (this.diag)
153               console.log(`rebuilding ${key} reason ${result.deps[i]}`)
154             result.deps = [key]
155             result.time = Date.now()
156             await this.build(key, result)
157             break
158           }
159         }
160       }
161     )()
162     try {
163       await result.done
164     }
165     catch (err) {
166       delete result.done
167       this.map.delete(key)
168       throw err
169     }
170     delete result.done
171   }
172   else
173     await result.done
174   let value = result.value
175   if (once)
176     result.value = undefined
177   return value
178 }
179
180 /**
181  * Call this periodically to allow the cache to clean itself of stale objects.
182  * It can be called as often as convenient, but since the cache can be large,
183  * the frequency of calls to "kick()" should be kept low. For example, if
184  * unreferenced objects should be kept for one day, then call "kick()" once
185  * per hour, and the actual lifetime will be at least 24 and up to 25 hours.
186  *
187  * The cache cleaning is not yet implemented, but the dummy "kick()" function
188  * is provided so that you can start to put the cleaning infrastructure in your
189  * code already. The constructor arguments might change later for this feature.
190  *
191  * @method
192  */
193 BuildCache.prototype.kick = function() {
194   // not yet implemented
195 }
196
197 module.exports = BuildCache
198 </code></pre>
199         </article>
200     </section>
201
202
203
204
205 </div>
206
207 <nav>
208     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="BuildCache.html">BuildCache</a></li></ul>
209 </nav>
210
211 <br class="clear">
212
213 <footer>
214     Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.3</a> on Wed Feb 05 2020 00:11:43 GMT+1100 (Australian Eastern Daylight Time)
215 </footer>
216
217 <script> prettyPrint(); </script>
218 <script src="scripts/linenumber.js"> </script>
219 </body>
220 </html>