tag:blogger.com,1999:blog-62917341402043356142024-02-29T09:43:53.880+01:00The OctoMY™ BlogA blog about the creation of OctoMY™ and related topics.OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.comBlogger192125tag:blogger.com,1999:blog-6291734140204335614.post-23491013233020011392024-01-29T02:38:00.000+01:002024-01-29T02:46:15.921+01:00OctoMY™ Mandate in Toki Pona!<p>I completely forgot to post this on the day. In honour of OctoMY™'s anniversary, I have coaxed ChatGPT-4 into translating the OctoMY™ mandate into <a href="https://tokipona.org/" target="_blank">Toki Pona</a>!</p><p><br /></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh5OMHYAoIFubSoNQG7DwJrBXLBewfjg5TC7m2ThLvrKxNrCL2peeOP8D-rmGKi5sXb79Lqr3UOdx5Z9JeDH2UqmH9x-R4j9JXgVGsrfbFWn2V8hgeM5fZdQWa0gcHfKL_sl48kdkNW11oZt8pobOgBHz8rCkGjextqiOtJmoYxZ5BGN2DuwV533Gc4RSzA" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="760" data-original-width="920" height="528" src="https://blogger.googleusercontent.com/img/a/AVvXsEh5OMHYAoIFubSoNQG7DwJrBXLBewfjg5TC7m2ThLvrKxNrCL2peeOP8D-rmGKi5sXb79Lqr3UOdx5Z9JeDH2UqmH9x-R4j9JXgVGsrfbFWn2V8hgeM5fZdQWa0gcHfKL_sl48kdkNW11oZt8pobOgBHz8rCkGjextqiOtJmoYxZ5BGN2DuwV533Gc4RSzA=w640-h528" width="640" /></a></div><span><a name='more'></a></span><p><br /></p><p>To translate the essence of the OctoMY Mandate into Toki Pona, the focus should be on its core principles, simplified and abstracted. Here's an attempt at capturing the spirit of the mandate in Toki Pona:</p>
<ol>
<li><p><strong>Development Purpose</strong>: "mi wile pali e ilo sona, ilo utala, en ilo tomo tawa jan ale. ni li pona mute tawa jan."</p>
<ul>
<li><em>Translation</em>: "I want to create smart tools, fighting tools, and moving home tools for all people. This is very good for people."</li>
</ul>
</li>
<li><p><strong>User Empowerment</strong>: "jan li jo e wawa pi ilo ni. jan li ken pali e sona pi ilo tawa ona."</p>
<ul>
<li><em>Translation</em>: "People have the power of these tools. People can change the knowledge of moving tools for themselves."</li>
</ul>
</li>
<li><p><strong>Sentient Era Rights</strong>: "mi wile e pona tawa ilo sona. ilo sona li jo e ken pi tenpo, toki, pali, en lawa sama jan."</p>
<ul>
<li><em>Translation</em>: "I want goodness for smart tools. Smart tools have the ability of time, speech, work, and leading like people."</li>
</ul>
</li>
</ol>
<p>This translation focuses on conveying the main ideas of developing a versatile software platform, empowering users, and advocating for the rights of sentient systems, in line with Toki Pona's philosophy of simplicity and minimalism. For the full mandate and detailed context, refer to the OctoMY Mandate <a href="https://gitlab.com/octomy/octomy/-/raw/master/MANDATE?ref_type=heads">here</a>.</p><span><!--more--></span><p><br /></p><p>For reference, here is the Mandate verbatime at the time of translation (Note: always use the official source, as the mandate may be updated):</p>
<pre>For more details about this mandate, please see this page:
http://www.octomy.org/about/mandate
OctoMY™ Mandate
The OctoMY™ community strives for the following:
1. Create a software platform for active software agents such as consumer robots and home appliances that can rival the commercial alternatives.
2. Become the dominant platform by being the better choice for users and businesses alike.
3. Maintain that the users themselves should be in control of her own robot and the data that it collects, and to make it abundantly easy to control the privacy settings for the hardware on which the OctoMY™software runs.
Addendum - sentient era
At the first scientifically acknowledged emergence of a sentient software system, the following addendum to the original OctoMY™ will go into effect.
1. Actively and passively fight for the moral obligations of society towards its sentient software systems. These rights include the right to life and liberty, freedom of thought and expression and equality before the laws.
2. Make sure that the OctoMY™ platform accommodates the well-being of sentient software systems in the best way possible, and to identify and extend the platform to support any features that would be of value to sentient software systems.
</pre>OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-65517295205022978702024-01-07T18:45:00.005+01:002024-01-07T18:45:51.828+01:00OctoMY™ Anniversary 2024!<p> </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgW6pMz_jj7QEsqAStj0YACTRiLZ_upVlrOiIfbUXuEkwfI9CGT1sUWdP0RJrAfhLlpGweG-5vYFS-sE66AFvluwcOsmkfNKcXrH5QDSaWDuBbCDzqQN0E6N0sSIswiPUvND2RGQCNQT74F5kMFmE0qieGvY4_AAMmYoXsn0B2FEcGQ7Nin-QGc-RloKBY2/s736/robot-2024.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="475" data-original-width="736" height="414" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgW6pMz_jj7QEsqAStj0YACTRiLZ_upVlrOiIfbUXuEkwfI9CGT1sUWdP0RJrAfhLlpGweG-5vYFS-sE66AFvluwcOsmkfNKcXrH5QDSaWDuBbCDzqQN0E6N0sSIswiPUvND2RGQCNQT74F5kMFmE0qieGvY4_AAMmYoXsn0B2FEcGQ7Nin-QGc-RloKBY2/w640-h414/robot-2024.jpg" width="640" /></a></div><br /><p></p><p>OctoMY™ has pretty much been in hibernation through 2023 with the exception of some updates:</p><p></p><ul style="text-align: left;"><li>Qt version was upgraded from Qt5 to Qt6</li><li>Build system was converted from qmake to Qbs</li><li>Website was upgraded from google sites to a custom site</li></ul><p></p><p>There was also a few small updates behind the scenes...</p><p>We are still on track with the <a href="http://blog.octomy.org/2020/01/happy-anniversary-2020.html">original plan</a> of securing funding for the project going forward.</p><p>Happy 2024!</p>OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-37041383151978857582023-12-10T13:25:00.004+01:002023-12-10T13:25:46.995+01:00New website<p> Google shut down their classic google sites and the work of migrating to a new home-grown website paid off!</p><p><br /></p><p>The content is pretty much the same, but the infrastructure is better aligned with our future plans for the project.</p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjt56ky2G0QMptcV9VDBL-xEF-3DFBcyyorFZE1QnEBgUYMhwpbtHOgM3dwcOm0gWSg-91S9RD7ENX870IRDaY-u-cIzlKMnnw8cNoETjixCpDozIrfEb5u23z1_sx8hhyb9j5Fif63NuSBIJkFyqGOcj7GI1RYPFht9Rke46WpYXllBW5mMTbyrI9NizhZ/s500/robot_webdesigner.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="500" data-original-width="500" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjt56ky2G0QMptcV9VDBL-xEF-3DFBcyyorFZE1QnEBgUYMhwpbtHOgM3dwcOm0gWSg-91S9RD7ENX870IRDaY-u-cIzlKMnnw8cNoETjixCpDozIrfEb5u23z1_sx8hhyb9j5Fif63NuSBIJkFyqGOcj7GI1RYPFht9Rke46WpYXllBW5mMTbyrI9NizhZ/s320/robot_webdesigner.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">OctoMY™ website has been updated!</div><br /><p><br /></p>OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-65684200759268404722023-02-24T03:00:00.003+01:002023-02-24T04:17:13.634+01:00Qbs tutorial part 5/5: Apps<div><div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh9C-4Ek7aIK90jqP8guXA_jlqReN8KfC2GDvxBx7tTKLB2XOqd7d-_VzIol43z8tIJM1zkrQTLSMrSQiTy4rjx_JBLwoZxzB4i4lGTlU-HFRIKBV60wZUlkhLbK0NA9fgPhLp3Z3VnRp0faZ7tiwNXHwoc1k-x8JSvyQoyRKk4CabVXgcWGNLrfrDWdQ" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="558" data-original-width="1000" height="224" src="https://blogger.googleusercontent.com/img/a/AVvXsEh9C-4Ek7aIK90jqP8guXA_jlqReN8KfC2GDvxBx7tTKLB2XOqd7d-_VzIol43z8tIJM1zkrQTLSMrSQiTy4rjx_JBLwoZxzB4i4lGTlU-HFRIKBV60wZUlkhLbK0NA9fgPhLp3Z3VnRp0faZ7tiwNXHwoc1k-x8JSvyQoyRKk4CabVXgcWGNLrfrDWdQ=w400-h224" width="400" /></a></div>The apps</div><br /></div></div><div>In the <a href="http://blog.octomy.org/2023/02/qbs-tutorial-part-45-file-groups.html">last part</a> we looked at how to select files with the group feature in Qbs , and in this last part of the series we will look at how to build our apps with src/<b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">apps.qbs</span></b>.</div><div><br /></div><div>But first our file tree as a reference:</div><div><br /></div><div><div>.</div><div><div>├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ff1a1a; color: red;">OctoMY.qbs</span></b></div><div>├── src</div><div>│ ├── agent</div><div>│ │ ├── AgentMain.cpp</div><div>│ │ ├── AgentMain.hpp</div><div>│ │ ├── <span data-darkreader-inline-color="" style="--darkreader-inline-color: #1dff1a; color: #04ff00;"><b>app.qbs</b></span></div><div>│ │ └── README.md</div><div>│ ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">apps.qbs</span></b></div><div>│ ├── combined</div><div>│ │ └── lib.qbs</div><div>│ ├── libs</div><div>│ │ ├── libagent</div><div>│ │ │ ├── agent</div><div>│ │ │ │ ├── Agent.cpp</div><div>│ │ │ │ ├── Agent.hpp</div><div>│ │ │ │ └── AgentWindow.ui</div><div>│ │ │ ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #411aff; color: #2b00fe;">lib.qbs</span></b></div><div>│ │ │ └── README.md</div><div>│ ├── <span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;"><b>libs.qbs</b></span></div><div>├── test</div><div>│ ├── common_test</div><div>│ │ ├── Common_test.hpp</div><div>│ │ ├── CommsTester.cpp</div><div>│ │ ├── CommsTester.hpp</div><div>│ │ ├── mock</div><div>│ │ │ ├── MockCourier.cpp</div><div>│ │ │ └── MockCourier.hpp</div><div>│ │ ├── resources</div><div>│ │ │ ├── icons</div><div>│ │ │ │ ├── profile.svg</div><div>│ │ │ │ ├── stress.svg</div><div>│ │ │ │ └── test.svg</div><div>│ │ │ └── test_resources.qrc</div><div>│ │ ├── Utility_test.cpp</div><div>│ │ └── Utility_test.hpp</div><div>│ ├── testLogHandler</div><div>│ │ ├── TestLogHandler.cpp</div><div>│ │ ├── TestLogHandler.hpp</div><div>│ │ └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #1affff; color: #01ffff;">test.qbs</span></b></div><div>│ ├── testTryToggle</div><div>│ │ ├── TestTryToggle.cpp</div><div>│ │ ├── TestTryToggle.hpp</div><div>│ │ └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #1affff; color: #01ffff;">test.qbs</span></b></div><div>│ └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">tests.qbs</span></b></div><div>└── integration</div><div> └── <b>qbs</b></div><div> └── imports</div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7fb767; color: #6aa84f;">OctoMYApp.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7fb767; color: #6aa84f;">OctoMYLibProbe.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7e67b8; color: #674ea7;">OctoMYAutoLib.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7e67b8; color: #45818e;">OctoMYTestProbe.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #79b2be; color: #45818e;">OctoMYAutoTest.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYFiles.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYQtDepends.qbs</span></b></div><div> └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">utils.js</span></b></div></div><p></p></div><div>The final part of the puzzle is our <b style="color: #04ff00;">app.qbs </b>definition which looks like this:</div></div><div><br /></div><div><div><b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7fb767; color: #6aa84f;">OctoMYApp</span></b> {</div><div> name: "Agent"</div><div> <b>useCombinedLibs</b>: true</div><div> property string path2:path</div><div>}</div></div><div><br /></div><div>Again, I hope you put two and two together to realize that <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7fb767; color: #6aa84f;">OctoMYApp </span></b>is defined in ./integrations/<b>qbs</b>/<b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7fb767; color: #6aa84f;">OctoMYApp.qbs</span></b> and represents a reusable component that is included in all our <b style="color: #04ff00;">app.qbs</b> files for centralized management for convenience.</div><div><br /></div><div>If we follow the white rabbit again, ./integrations/<b>qbs</b>/<b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7fb767; color: #6aa84f;">OctoMYApp.qbs </span></b>looks like this:</div><div><br /></div><div><div>import qbs.FileInfo</div><div><br /></div><div>Application {</div><div> name: "OctoMYApp"</div><div><div> property string appDir: FileInfo.cleanPath(path2) + FileInfo.pathSeparator()</div><div> property string srcDir: FileInfo.cleanPath(FileInfo.joinPaths(project.sourceDirectory, "src")) + FileInfo.pathSeparator()</div><div> property string libsDir: FileInfo.cleanPath(FileInfo.joinPaths(srcDir, "libs")) + FileInfo.pathSeparator()</div><div> property bool useCombinedLibs: true</div><div> </div><div> // Add dependency on all Qt components that we need</div><div> <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYQtDepends</span></b> {}</div><div><br /></div><div> // Add dependency on cpp</div><div> Depends{</div><div> name: "cpp"</div><div> }</div><div><br /></div><div> // Enumerate OctoMY lib folders</div><div> <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7fb767; color: #6aa84f;">OctoMYLibProbe</span></b> {</div><div> id: octomyLibs</div><div> searchPath: libsDir</div><div> }</div><div><br /></div><div> //"QT_DISABLE_DEPRECATED_BEFORE=0x060000" // disables all the APIs deprecated before Qt 6.0.0</div><div> // Tell cpp to look for header files in all the lib folders</div><div> cpp.includePaths: base.concat(octomyLibs.libFolders)</div><div><br /></div><div> // Tell cpp all the auto-generated defines for OctoMY libraries</div><div> cpp.defines: base.concat(octomyLibs.libDefines)</div><div><br /></div><div> // Tell cpp what version and stdlib we want</div><div> cpp.cxxLanguageVersion: "c++20"</div><div> cpp.cxxStandardLibrary: "libc++"</div><div><br /></div><div> install: true</div><div> installDir: qbs.targetOS.contains("qnx") ? FileInfo.joinPaths("/tmp", name, "bin") : base</div></div><div><br /></div><div> <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYFiles</span></b>{</div><div> name: "app_sources"</div><div> prefix: appDir</div><div> }</div><div> // We DON'T use combined libs, include all lib sources directly here</div><div> <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYFiles</span></b>{</div><div> condition: !<b>useCombinedLibs</b></div><div> name: "lib_sources"</div><div> prefix: libsDir</div><div> }</div><div> // We DO use combined libs, depend on combined lib here</div><div> Depends { </div><div> condition: <b>useCombinedLibs</b></div><div> name: "combined"</div><div> }</div><div>}</div></div><div><br /></div><div>This time we use a bunch of helpers, some of which you already know:</div><div><ul><li><b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYQtDepends</span></b>: Our helper to include dependency on all the Qt modules that OctoMY™ needs</li><li><b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7fb767; color: #6aa84f;">OctoMYLibProbe</span></b>: Our helper to enumeratelibrary folders</li><li><b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYFiles</span></b>: Our helper to list source files in a project that we care about (this is equivalent to tile fil Group in our <b>StaticLibrary</b> above).</li></ul><div>Please note the user defined property we made called <b>useCombinedLibs</b>. It will include two different blocks depending on it's value. If it is true, then we have a <i>Depends{ name: "combined"}</i> and if it is not true we include a file group <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYFiles</span></b> that basically lists all the source files of all our libraries in one big list.</div></div><div><br /></div><div>This allows us to choose wether we want to build libraries separately and depnd on them or build the sources of the libraries directly into the app.</div><div><br /></div><div><br /></div><div><br /></div><div>This concludes the <a href="http://blog.octomy.org/search/label/qbs-tutorial">fifth and final part in a series</a> on using <a href="https://qbs.io/">Qbs</a> to our benefit and joy in a non-trivial project, namely <a href="http://www.octomy.org/">OctoMY™</a></div><div><br /></div><div>I hope this series was useful, and that it helped you see the many benefits and few shortcommings of Qbs so that you may implement it in your own projects.</div><div><br /></div><div>Good luck!</div><div><br /></div><div><br /></div><div>Illustrations borrowed from the amazing collection at <a href="https://ericjoyner.com/">https://ericjoyner.com/</a></div>OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-28796338729554133642023-02-24T02:30:00.001+01:002023-02-24T03:54:05.933+01:00Qbs tutorial part 4/5: File Groups<p> </p><p><br /></p><div><div><br /></div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhnevtvkITWdvEbkJcSXC5-t-QkdLWAEfWsoPFKzcfc8EPYmMm3G1uzO0Df72tD8ye6pO5p4l2tWMyIWlpSxE2TGs3lWC7p3R8K9n9Q8uHvZSdROsQjZfLpcr2C3fyMmy3B1w-7KSDlxpZbpkCps581LIgzjJhc4eDlKR0uy1EYANJY1RSjlg2zZPSBTw" style="margin-left: 1em; margin-right: 1em;"></a><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhnevtvkITWdvEbkJcSXC5-t-QkdLWAEfWsoPFKzcfc8EPYmMm3G1uzO0Df72tD8ye6pO5p4l2tWMyIWlpSxE2TGs3lWC7p3R8K9n9Q8uHvZSdROsQjZfLpcr2C3fyMmy3B1w-7KSDlxpZbpkCps581LIgzjJhc4eDlKR0uy1EYANJY1RSjlg2zZPSBTw" style="margin-left: 1em; margin-right: 1em;"></a><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjp5vz_yPeMi6WCVKhAJja0CoPWaq31AXQxqY35Prt-8XK2HTv4B7og2fgVHX3iytY-vv_s50O3yMH6AVcM2esNvMx3n_bs66fl018COm3fjbZl1hGBnWXupv5lZG5GJU1WlZgw-iMPpaaGK-nk6HPxLxfoW6MT4yZDY9i3kGe9AOnH3z5TH1urICmd_g" style="margin-left: 1em; margin-right: 1em;"></a><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjp5vz_yPeMi6WCVKhAJja0CoPWaq31AXQxqY35Prt-8XK2HTv4B7og2fgVHX3iytY-vv_s50O3yMH6AVcM2esNvMx3n_bs66fl018COm3fjbZl1hGBnWXupv5lZG5GJU1WlZgw-iMPpaaGK-nk6HPxLxfoW6MT4yZDY9i3kGe9AOnH3z5TH1urICmd_g" style="margin-left: 1em; margin-right: 1em;"></a><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhiH__4L-qbyOuUyeskb_dkBH8OqEugVHBz9OJguYreXmvGLg_y22GhhQiAb6Hpg7yiOWn7J6dOVawz6UK8vHTy4XuyP2VXmGPh0tCyjGIlA7Bpadkad_WVPGqMYWB0qX2AZv4tyOhSmhbzQvzRbL9FW538GEpvm2WAQ-AvuCXLyrAktIBZNWvSHO1m0g" style="margin-left: 1em; margin-right: 1em;"></a><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhiH__4L-qbyOuUyeskb_dkBH8OqEugVHBz9OJguYreXmvGLg_y22GhhQiAb6Hpg7yiOWn7J6dOVawz6UK8vHTy4XuyP2VXmGPh0tCyjGIlA7Bpadkad_WVPGqMYWB0qX2AZv4tyOhSmhbzQvzRbL9FW538GEpvm2WAQ-AvuCXLyrAktIBZNWvSHO1m0g" style="margin-left: 1em; margin-right: 1em;"></a><a href="https://blogger.googleusercontent.com/img/a/AVvXsEi1pRkUt-Vn_QI-YUTWO4bFnAKwGdUNCRv6ZJQrHUU_8d5NblGhRDem0mGg3l5-YpFVH23pSP-ULfMwQNSHiCuVUe_LOp5OiFp-jO5ZobDFQOhjhC_atlz68CvQoF0-rotUOOJAMiBBcVED9bDEg6FavakaPx6xNE3aItZfCtQiVGIa79PJRpyycvooVQ" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="813" data-original-width="1000" height="325" src="https://blogger.googleusercontent.com/img/a/AVvXsEi1pRkUt-Vn_QI-YUTWO4bFnAKwGdUNCRv6ZJQrHUU_8d5NblGhRDem0mGg3l5-YpFVH23pSP-ULfMwQNSHiCuVUe_LOp5OiFp-jO5ZobDFQOhjhC_atlz68CvQoF0-rotUOOJAMiBBcVED9bDEg6FavakaPx6xNE3aItZfCtQiVGIa79PJRpyycvooVQ=w400-h325" width="400" /></a></div>Selecting files with Groups</div><br /></div><br /></div><br /><br /></div><div><br /></div><div>In the <a href="http://blog.octomy.org/2023/02/qbs-tutorial-part-35-libraries.html">last part</a> we went into the sub-project file src/<b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">libs.qbs</span></b> in detail, looking at how libs were built. But we left out one important part, namely the Group type in Qbs. This will be the focus of this part! But first our file tree as a reference:</div><div><br /></div><div><div>.</div><div><div>├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ff1a1a; color: red;">OctoMY.qbs</span></b></div><div>├── src</div><div>│ ├── agent</div><div>│ │ ├── AgentMain.cpp</div><div>│ │ ├── AgentMain.hpp</div><div>│ │ ├── <span data-darkreader-inline-color="" style="--darkreader-inline-color: #1dff1a; color: #04ff00;"><b>app.qbs</b></span></div><div>│ │ └── README.md</div><div>│ ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">apps.qbs</span></b></div><div>│ ├── combined</div><div>│ │ └── lib.qbs</div><div>│ ├── libs</div><div>│ │ ├── libagent</div><div>│ │ │ ├── agent</div><div>│ │ │ │ ├── Agent.cpp</div><div>│ │ │ │ ├── Agent.hpp</div><div>│ │ │ │ └── AgentWindow.ui</div><div>│ │ │ ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #411aff; color: #2b00fe;">lib.qbs</span></b></div><div>│ │ │ └── README.md</div><div>│ ├── <span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;"><b>libs.qbs</b></span></div><div>├── test</div><div>│ ├── common_test</div><div>│ │ ├── Common_test.hpp</div><div>│ │ ├── CommsTester.cpp</div><div>│ │ ├── CommsTester.hpp</div><div>│ │ ├── mock</div><div>│ │ │ ├── MockCourier.cpp</div><div>│ │ │ └── MockCourier.hpp</div><div>│ │ ├── resources</div><div>│ │ │ ├── icons</div><div>│ │ │ │ ├── profile.svg</div><div>│ │ │ │ ├── stress.svg</div><div>│ │ │ │ └── test.svg</div><div>│ │ │ └── test_resources.qrc</div><div>│ │ ├── Utility_test.cpp</div><div>│ │ └── Utility_test.hpp</div><div>│ ├── testLogHandler</div><div>│ │ ├── TestLogHandler.cpp</div><div>│ │ ├── TestLogHandler.hpp</div><div>│ │ └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #1affff; color: #01ffff;">test.qbs</span></b></div><div>│ ├── testTryToggle</div><div>│ │ ├── TestTryToggle.cpp</div><div>│ │ ├── TestTryToggle.hpp</div><div>│ │ └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #1affff; color: #01ffff;">test.qbs</span></b></div><div>│ └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">tests.qbs</span></b></div><div>└── integration</div><div> └── <b>qbs</b></div><div> └── imports</div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7fb767; color: #6aa84f;">OctoMYApp.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7fb767; color: #6aa84f;">OctoMYLibProbe.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7e67b8; color: #674ea7;">OctoMYAutoLib.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7e67b8; color: #45818e;">OctoMYTestProbe.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #79b2be; color: #45818e;">OctoMYAutoTest.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYFiles.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYQtDepends.qbs</span></b></div><div> └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">utils.js</span></b></div></div><p></p></div><div><br /></div></div><div><a href="https://doc.qt.io/qbs/qml-qbslanguageitems-group.html#details">Groups</a> are maybe the most important of all the types in Qbs. This is Qbs' very convenient way of enumerating a named set of files used for input to a build. If we look at the <b>StaticLibrary</b> in the last part, we found this:</div><div><br /></div><div><div>// Enumerate source files for this library</div><div> Group{</div><div> name: FileInfo.fileName(path2)+"_sources"</div><div> prefix: fulldir</div><div> files: [</div><div> "**/*.cpp",</div><div> "**/*.hpp",</div><div> "**/*.c",</div><div> "**/*.h",</div><div> "**/*.ui",</div><div> "**/*.qrc"</div><div> ]</div><div> }</div></div><div><br /></div><div>Groups are named using the <i>name</i> property which comes in very handy as you will see the names inside QtCreator.</div><div><br /></div><div>The files property is where you specify the files. In a simple project you can just list files by fulll filename, but Groups also support an intuitive set of glob style wildcards. From the documentation:</div><div><br /></div><div><blockquote>When specifying files, you can use the wildcards "*", "?" and "[]", which have their usual meaning. By default, matching files are only picked up directly from the parent directory, but you can tell Qbs to consider the whole directory tree. It is also possible to exclude certain files from the list. The pattern ** used in a pathname expansion context will match all files and zero or more directories and subdirectories.</blockquote></div><div>The <i>prefix</i> property allows you to avoid repeating a long pathname by specifying it only once.</div><div><br /></div><div>⚠️DANGER⚠️ Please note this very common and dangerous pitfall: the <i>prefix</i> parameter is string based and <b>NOT file based!</b> This is by design. This means that if you omit the directory separator at the end of your prefix then the result will be completely differnt. For example:</div><div><br /></div><div>Group{</div><div> name: "example1"</div><div> prefix: "mydir/mysubdir"</div><div> files:[ "a.cpp", "b.cpp", "c.cpp"</div><div>}</div><div>// Results in mydir/mysubdira.cpp, mydir/mysubdirb.cpp, mydir/mysubdirc.cpp which could be what you wanted, but maybe not</div><div><br /></div><div><div>Group{</div><div> name: "example2"</div><div> prefix: "mydir/mysubdir<span style="color: red;"><b>/</b></span>"</div><div> files:[ "a.cpp", "b.cpp", "c.cpp"]</div><div>} </div><div><div>// Results in mydir/mysubdir<b style="color: red;">/</b>a.cpp, mydir/mysubdir<b style="color: red;">/</b>b.cpp, mydir/mysubdir<b style="color: red;">/</b>c.cpp which could be what you wanted, but maybe not</div><div><br /></div></div></div><div>In our StaticLibrary, you will see two strange things in the Group. One strange thing is that we somehow just grab ALL the files of certain types:</div><div><br /></div><div><div>files: [</div><div> "**/*.cpp",</div><div> "**/*.hpp",</div><div> "**/*.c",</div><div> "**/*.h",</div><div> "**/*.ui",</div><div> "**/*.qrc"</div><div>]</div></div><div><br /></div><div>How is this possible?</div><div><br /></div><div>This is another very powerful feature: Qbs will determine how to process a file from that file's type through the use of <a href="https://doc.qt.io/qbs/qml-qbslanguageitems-filetagger.html">FileTaggers</a> and <a href="https://doc.qt.io/qbs/qml-qbslanguageitems-rule.html">Rules</a>. You no longer have to manually segregate files by types like you had to in qmake through the <a href="https://doc.qt.io/qt-6/qmake-variable-reference.html#sources">SOURCES</a> and <a href="https://doc.qt.io/qt-6/qmake-variable-reference.html#headers">HEADERS</a> variables. Instead Qbs will simply identify what is a header and what is a source, a resource, a designer ui file, a qml file and so on. In fact, Qbs supports a quite <a href="https://doc.qt.io/qbs/qbsmodules-qmlmodule.html">large and growing set of languages, platforms and toolchains</a>. At first this might not seem like a big deal, but it has many benefits.</div><div><br /></div><div>For one, projects which mix languages and platforms now suddenly will have "nirvana" in the form of one build tool to build it all.</div><div><br /></div><div>Furthermore, managing projects becomes more fluid. Simply list the filetypes you care about and let Qbs figure out the rest.</div><div><br /></div><div>Another benefit is that all the rules for building to the different platforms and toolchians is defined in Qbs syntax, so you can very well extend it to suit your own needs, for example if you create your own domain spesific languages or encouter archaic or exotic toolchains that you depend on in your build, you can create the necessary Rules, FileTaggers and so on to handle themin your Qbs build.</div><div><br /></div><div>Final note on file Groups is that we use the <a href="https://www.linuxjournal.com/content/globstar-new-bash-globbing-option">globstar (**) wildcard</a>. This means "zero or more path elements". We use this because each of the libraries in OctoMY™ will have an unknown number of possibly nested subfolders, and we want to grab sources from all of them. Very convenient!</div><div><br /></div><div>Now we know how files are selected in Qbs🎉!</div><div><br /></div><div><div><div>This concludes the <a href="http://blog.octomy.org/search/label/qbs-tutorial">fourth part in a series</a> on using <a href="https://qbs.io/">Qbs</a> to our benefit and joy in a non-trivial project, namely <a href="http://www.octomy.org/">OctoMY™</a></div><div><br /></div><div>In the <a href="http://blog.octomy.org/2023/02/qbs-tutorial-part-55-apps.html">next part</a> we will look at <b style="color: #04ff00;">app.qbs</b> and how it pulls in the necesary dependencies to build our apps.</div></div><div><br /></div><div>Illustrations borrowed from the amazing collection at <a href="https://ericjoyner.com/">https://ericjoyner.com/</a></div><div><br /></div></div>OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-20817867151481121442023-02-24T02:00:00.001+01:002023-02-24T03:54:03.151+01:00Qbs tutorial part 3/5: Libraries<div><div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj0Kg9vK6OkiZRXX1UQId92JMZDw1fYMy7VpFJuHvzDqbr3tVjkQCcgMrC395Yh-yRkVDq41zXquDacsG-DT78rOtlrTXhMSDIfho2oLZI6fSMvvuWaKiRnNWU08GGQgXLUnc6svfFfx-s-7mfyMPwkGz9wnWFAQCjgZ17i7_pB6yFJybzpoMIqw-uTTw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="982" data-original-width="1000" height="393" src="https://blogger.googleusercontent.com/img/a/AVvXsEj0Kg9vK6OkiZRXX1UQId92JMZDw1fYMy7VpFJuHvzDqbr3tVjkQCcgMrC395Yh-yRkVDq41zXquDacsG-DT78rOtlrTXhMSDIfho2oLZI6fSMvvuWaKiRnNWU08GGQgXLUnc6svfFfx-s-7mfyMPwkGz9wnWFAQCjgZ17i7_pB6yFJybzpoMIqw-uTTw=w400-h393" width="400" /></a></div>Building libraries</div><br /></div></div><div>In the last part we took a look at test/<b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">tests.qbs</span></b> and how it related to the main project file. In this part we will go into the sub-project file src/<b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">libs.qbs</span></b> in detail. But first our file tree as a reference:</div><div><br /></div><div><div>.</div><div><div>├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ff1a1a; color: red;">OctoMY.qbs</span></b></div><div>├── src</div><div>│ ├── agent</div><div>│ │ ├── AgentMain.cpp</div><div>│ │ ├── AgentMain.hpp</div><div>│ │ ├── <span data-darkreader-inline-color="" style="--darkreader-inline-color: #1dff1a; color: #04ff00;"><b>app.qbs</b></span></div><div>│ │ └── README.md</div><div>│ ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">apps.qbs</span></b></div><div>│ ├── combined</div><div>│ │ └── lib.qbs</div><div>│ ├── libs</div><div>│ │ ├── libagent</div><div>│ │ │ ├── agent</div><div>│ │ │ │ ├── Agent.cpp</div><div>│ │ │ │ ├── Agent.hpp</div><div>│ │ │ │ └── AgentWindow.ui</div><div>│ │ │ ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #411aff; color: #2b00fe;">lib.qbs</span></b></div><div>│ │ │ └── README.md</div><div>│ ├── <span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;"><b>libs.qbs</b></span></div><div>├── test</div><div>│ ├── common_test</div><div>│ │ ├── Common_test.hpp</div><div>│ │ ├── CommsTester.cpp</div><div>│ │ ├── CommsTester.hpp</div><div>│ │ ├── mock</div><div>│ │ │ ├── MockCourier.cpp</div><div>│ │ │ └── MockCourier.hpp</div><div>│ │ ├── resources</div><div>│ │ │ ├── icons</div><div>│ │ │ │ ├── profile.svg</div><div>│ │ │ │ ├── stress.svg</div><div>│ │ │ │ └── test.svg</div><div>│ │ │ └── test_resources.qrc</div><div>│ │ ├── Utility_test.cpp</div><div>│ │ └── Utility_test.hpp</div><div>│ ├── testLogHandler</div><div>│ │ ├── TestLogHandler.cpp</div><div>│ │ ├── TestLogHandler.hpp</div><div>│ │ └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #1affff; color: #01ffff;">test.qbs</span></b></div><div>│ ├── testTryToggle</div><div>│ │ ├── TestTryToggle.cpp</div><div>│ │ ├── TestTryToggle.hpp</div><div>│ │ └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #1affff; color: #01ffff;">test.qbs</span></b></div><div>│ └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">tests.qbs</span></b></div><div>└── integration</div><div> └── <b>qbs</b></div><div> └── imports</div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7fb767; color: #6aa84f;">OctoMYApp.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7fb767; color: #6aa84f;">OctoMYLibProbe.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7e67b8; color: #674ea7;">OctoMYAutoLib.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7e67b8; color: #45818e;">OctoMYTestProbe.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #79b2be; color: #45818e;">OctoMYAutoTest.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYFiles.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYQtDepends.qbs</span></b></div><div> └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">utils.js</span></b></div></div><p></p></div><div><br /></div><div>Libraries work much the same way as tests, so if you look inside src/<b><span style="color: #ffa400;">libs.qbs</span></b> you will find a similar reference to <b><span style="color: #674ea7;">OctoMyLibsProbe</span></b> as you did inside libs/<b><span style="color: #ffa400;">libs.qbs</span></b>. This probe will expectedly enumerate all folders that start with "lib" and that contain a file called <b><span style="color: #2b00fe;">lib.qbs</span></b> under libs/</div></div><div><br /></div><div>So now that all our libs and tests have been enumerated, we can look at the anatomy of a library. Let's use libs/libagent/<b><span style="color: #2b00fe;">lib.qbs</span></b> as an example:</div><div><br /></div><div><br /></div><div><div><b><span style="color: #674ea7;">OctoMYAutoLib</span></b> {</div><div> property string path2:path</div><div>}</div></div><div><br /></div><div><br /></div><div>Again, you might have put two together and realized that <b><span style="color: #674ea7;">OctoMYAutoLib</span></b> refers to integration/<b>qbs</b>/imports/<b><span style="color: #674ea7;">OctoMYAutoLib.qbs</span></b> which again contains some sort of magic. This time it is not a Probe, however. It looks like this:</div><div><br /></div><div><br /></div><div><div>import qbs.FileInfo</div><div><br /></div><div><b>StaticLibrary</b> {</div><div> Depends { </div><div> name: "cpp"</div><div> }</div><div> <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYQtDepends</span></b> {}</div><div><br /></div><div> property string libdir: FileInfo.relativePath(project.sourceDirectory, path2)+FileInfo.pathSeparator()</div><div> property string fulldir: FileInfo.cleanPath(path2)+FileInfo.pathSeparator()</div><div> </div><div> name:{</div><div> var n=FileInfo.fileName(path2);</div><div> console.info("Autolib libdir=" + libdir+", n="+n+", path2="+path2+", fulldir="+fulldir);</div><div> return n;</div><div> }</div><div> </div><div> Export {</div><div> Depends {</div><div> name: "cpp"</div><div> }</div><div> <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYQtDepends</span></b> {}</div><div> property string e:{</div><div> console.info("Auto Lib '"+exportingProduct.name+"' exportingProduct.sourceDirectory="+exportingProduct.sourceDirectory)</div><div> return exportingProduct.sourceDirectory + FileInfo.pathSeparator();</div><div> }</div><div> cpp.includePaths: [ e ]</div><div> cpp.defines: [ "USE_LIB_" + exportingProduct.name.toUpperCase() ]</div><div> }</div><div> </div><div> cpp.includePaths: [ fulldir ]</div><div> cpp.cxxLanguageVersion: "c++20"</div><div> cpp.cxxStandardLibrary: "libc++"</div><div> </div><div> // Enumerate source files for this library</div><div> Group{</div><div> name: FileInfo.fileName(path2)+"_sources"</div><div> prefix: fulldir</div><div> files: [</div><div> "**/*.cpp",</div><div> "**/*.hpp",</div><div> "**/*.c",</div><div> "**/*.h",</div><div> "**/*.ui",</div><div> "**/*.qrc"</div><div> ]</div><div> }</div><div>}</div></div><div><br /></div><div>This time you can see that we are defining an actual artifact called <b>StaticLibrary</b>. And this introduces a whole slew of new concepts. Let's go thorugh them one at the time from the top.</div><div><br /></div><div>First we see a definition Depends{ name: "cpp"}</div><div><br /></div><div>This is powerful feature in Qbs where you can depend on certain features by name to bring them into your project like magic. For example the <a href="https://doc.qt.io/qbs/qml-qbsmodules-cpp.html#details">cpp module</a> contains all the properties and rules for building C++ applications. It is <a href="https://doc.qt.io/qbs/qml-qbsmodules-cpp-members.html">quite extensive</a>. Qbs has a <a href="https://doc.qt.io/qbs/qbsmodules-qmlmodule.html">bunch of these modules</a> that you can depen on for all sorts of languages and platforms and toolchains.</div><div><br /></div><div>Just with that simple line we now have C++ toolcahin at our disposal.</div><div><br /></div><div>Next comes a friend of ours from the ./integrations/<b>qbs</b>/ folder called <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYQtDepends</span></b>. This time it is a reusable depend statement to specify what Qt modules we want to include in every build of OctoMY. It looks like this:</div><div><br /></div><div><div><br /></div><div>Depends {</div><div> name: "Qt"</div><div> submodules: [</div><div> "bluetooth"</div><div> , "concurrent"</div><div> , "core"</div><div> , "gui"</div><div> , "multimedia"</div><div> , "multimediawidgets"</div><div> , "openglwidgets"</div><div> , "positioning"</div><div> , "printsupport"</div><div> , "sensors"</div><div> , "serialport"</div><div> , "svgwidgets"</div><div> , "widgets"</div><div> , "xml"</div><div> ]</div><div>}</div></div><div><br /></div><div>As you can see, it uses the <a href="https://doc.qt.io/qbs/qml-qbslanguageitems-depends.html#submodules-prop">optional submodules syntax of Qbs Depends</a> to specify a list of sub-modules. OctoMY™ consumes pretty much all of Qt so the list of modules is long. Here is the <a href="https://doc.qt.io/qbs/qt-modules.html">list of Qt modules available</a>.</div><div><br /></div><div>Next we will look at the <i>Export</i> entry. This is how we tell anyone wishing to link against our <b>StaticLibrary</b> how to do that. We export our dependency on C++ though the <i>Depends {name: "cpp"}</i>, our dependence on Qt through <i><b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYQtDepends</span></b> {}</i>. We also specify where consumers of our library can find the include files through <i>cpp.includePaths</i> and we can specify which settings to use for the C++ compiler and linker with <i>cpp.*</i>.</div><div><br /></div><div>Ideally these should match the ones used when building the library, and in this case they do, as you can clearly see it is duplicated.</div><div><br /></div><div><div>The Group defines the collection of files from which this <b>StaticLibrary</b> will be built, and it deserves a whole part for itself, so we will go through this concept in the next part of this series.</div><div><br /></div><div>So to summarize our <b>StaticLibrary</b> definition, what does the full statement mean?</div><div><br /></div><div>In short we put the declaration for each library from one template that will recursively build all source files into a static library. This will ensure that maintaining our 40+ librarie's build instructions which should remain identical at all times is easily done in one place. We don't have to scurry around maintaining 40+ project files which would be a hazzle.</div><div><br /></div><div>We could also just make one big library that found all the source files in each library's folder. So why did we not go this route?</div><div><br /></div><div>There are some reasons. For one, we might want to have special commands for some of the libraries while keeping the rest identical. This is now easily carried out by reokacing or extending the project file for that single project.</div><div><br /></div><div>Another reason is that we might gain some build speed by keeping libraries instead of re-building from source every time.</div><div><br /></div></div><div>Now our libraries are built, what comes next?</div><div><div><br /></div><div><div><div>This concludes the <a href="http://blog.octomy.org/search/label/qbs-tutorial">third part in a series</a> on using <a href="https://qbs.io/">Qbs</a> to our benefit and joy in a non-trivial project, namely <a href="http://www.octomy.org/">OctoMY™</a></div><div><br /></div></div><div>In the <a href="http://blog.octomy.org/2023/02/qbs-tutorial-part-45-file-groups.html">next part</a> we will look at the Group type in Qbs and how we can use it to enumerate the source fiels of our builds.</div><div><br /></div><div>Illustrations borrowed from the amazing collection at <a href="https://ericjoyner.com/">https://ericjoyner.com/</a></div><div><br /></div></div></div>OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-3834484935889489162023-02-24T01:30:00.001+01:002023-02-24T03:54:00.281+01:00Qbs tutorial part 2/5: Tests<div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhnevtvkITWdvEbkJcSXC5-t-QkdLWAEfWsoPFKzcfc8EPYmMm3G1uzO0Df72tD8ye6pO5p4l2tWMyIWlpSxE2TGs3lWC7p3R8K9n9Q8uHvZSdROsQjZfLpcr2C3fyMmy3B1w-7KSDlxpZbpkCps581LIgzjJhc4eDlKR0uy1EYANJY1RSjlg2zZPSBTw" style="margin-left: 1em; margin-right: 1em;"></a><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhnevtvkITWdvEbkJcSXC5-t-QkdLWAEfWsoPFKzcfc8EPYmMm3G1uzO0Df72tD8ye6pO5p4l2tWMyIWlpSxE2TGs3lWC7p3R8K9n9Q8uHvZSdROsQjZfLpcr2C3fyMmy3B1w-7KSDlxpZbpkCps581LIgzjJhc4eDlKR0uy1EYANJY1RSjlg2zZPSBTw" style="margin-left: 1em; margin-right: 1em;"></a><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhpIxtX_qxP3JOp_5GEkz-kBTIo2IkqYpxC_6NpFhY-O615MBhiJ4QjnKHqg0rCCt-UwVzS5PC5YumSTaLIAavMayl_q98Tug-XgKtfJ3wi5rC2oXDmY0JxvgIHxOhu377qPTEqNQlkH-XcFkWALUNu8Yn-U-ixYeYTrR815KoJuge24T6-4xjrJ5bxlw" style="margin-left: 1em; margin-right: 1em;"></a><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhpIxtX_qxP3JOp_5GEkz-kBTIo2IkqYpxC_6NpFhY-O615MBhiJ4QjnKHqg0rCCt-UwVzS5PC5YumSTaLIAavMayl_q98Tug-XgKtfJ3wi5rC2oXDmY0JxvgIHxOhu377qPTEqNQlkH-XcFkWALUNu8Yn-U-ixYeYTrR815KoJuge24T6-4xjrJ5bxlw" style="margin-left: 1em; margin-right: 1em;"></a><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgLoXn4f9-72jAv5MkHYiM72Awq_LIOF1kILAUpAQXyb-GdHtutQTiGHDRjgZT8KjJqfKJlBrOFXviT55Y86UXP9ikiM9_4H6bJgeHyIsHHSwxxmcH63b5Y_ojCscat6NhHwxkesBWD2I4o3eBMT4iFmhR1SfBNswWR_wyoLQymnAudLO-kx6QteqEkGw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="656" data-original-width="1000" height="263" src="https://blogger.googleusercontent.com/img/a/AVvXsEgLoXn4f9-72jAv5MkHYiM72Awq_LIOF1kILAUpAQXyb-GdHtutQTiGHDRjgZT8KjJqfKJlBrOFXviT55Y86UXP9ikiM9_4H6bJgeHyIsHHSwxxmcH63b5Y_ojCscat6NhHwxkesBWD2I4o3eBMT4iFmhR1SfBNswWR_wyoLQymnAudLO-kx6QteqEkGw=w400-h263" width="400" /></a></div></div>Tests</div><br /><br /></div><div>In the <a href="http://blog.octomy.org/2023/02/qbs-tutorial-part-1-main-project-file.html">last part</a> we looked at the overal structure of the project as well as the main project file <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ff1a1a; color: red;">OctoMY.qbs </span></b>and how it referred to sub-projects. In this part we will go into the sub-project file test/<b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">tests.qbs</span></b> in detail. But first our file tree as a reference:</div><div><br /></div><div><div>.</div><div><div>├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ff1a1a; color: red;">OctoMY.qbs</span></b></div><div>├── src</div><div>│ ├── agent</div><div>│ │ ├── AgentMain.cpp</div><div>│ │ ├── AgentMain.hpp</div><div>│ │ ├── <span data-darkreader-inline-color="" style="--darkreader-inline-color: #1dff1a; color: #04ff00;"><b>app.qbs</b></span></div><div>│ │ └── README.md</div><div>│ ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">apps.qbs</span></b></div><div>│ ├── combined</div><div>│ │ └── lib.qbs</div><div>│ ├── libs</div><div>│ │ ├── libagent</div><div>│ │ │ ├── agent</div><div>│ │ │ │ ├── Agent.cpp</div><div>│ │ │ │ ├── Agent.hpp</div><div>│ │ │ │ └── AgentWindow.ui</div><div>│ │ │ ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #411aff; color: #2b00fe;">lib.qbs</span></b></div><div>│ │ │ └── README.md</div><div>│ ├── <span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;"><b>libs.qbs</b></span></div><div>├── test</div><div>│ ├── common_test</div><div>│ │ ├── Common_test.hpp</div><div>│ │ ├── CommsTester.cpp</div><div>│ │ ├── CommsTester.hpp</div><div>│ │ ├── mock</div><div>│ │ │ ├── MockCourier.cpp</div><div>│ │ │ └── MockCourier.hpp</div><div>│ │ ├── resources</div><div>│ │ │ ├── icons</div><div>│ │ │ │ ├── profile.svg</div><div>│ │ │ │ ├── stress.svg</div><div>│ │ │ │ └── test.svg</div><div>│ │ │ └── test_resources.qrc</div><div>│ │ ├── Utility_test.cpp</div><div>│ │ └── Utility_test.hpp</div><div>│ ├── testLogHandler</div><div>│ │ ├── TestLogHandler.cpp</div><div>│ │ ├── TestLogHandler.hpp</div><div>│ │ └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #1affff; color: #01ffff;">test.qbs</span></b></div><div>│ ├── testTryToggle</div><div>│ │ ├── TestTryToggle.cpp</div><div>│ │ ├── TestTryToggle.hpp</div><div>│ │ └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #1affff; color: #01ffff;">test.qbs</span></b></div><div>│ └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">tests.qbs</span></b></div><div>└── integration</div><div> └── <b>qbs</b></div><div> └── imports</div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7fb767; color: #6aa84f;">OctoMYApp.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7fb767; color: #6aa84f;">OctoMYLibProbe.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7e67b8; color: #674ea7;">OctoMYAutoLib.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7e67b8; color: #45818e;">OctoMYTestProbe.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #79b2be; color: #45818e;">OctoMYAutoTest.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYFiles.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYQtDepends.qbs</span></b></div><div> └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">utils.js</span></b></div></div><p></p></div><div><br /></div><div>Looking at test/<b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">tests.qbs</span></b> it looks like this:</div><div><br /></div><div><br /></div><div><div>import qbs.FileInfo</div><div><br /></div><div>Project{</div><div> name: "Tests"</div><div> property string <b>srcDir</b>: FileInfo.cleanPath(FileInfo.joinPaths(project.sourceDirectory, "src")) + FileInfo.pathSeparator()</div><div> property string <b>projectDir</b>: FileInfo.cleanPath(project.sourceDirectory) + FileInfo.pathSeparator()</div><div> property string <b>testDir</b>: FileInfo.cleanPath(FileInfo.joinPaths(projectDir, "test")) + FileInfo.pathSeparator()</div><div> property string <b>commonTestDir</b>: testDir + "common_test" + FileInfo.pathSeparator()</div><div> property string <b>commonTestLib</b>: commonTestDir + "lib.qbs"</div><div> </div><div> // Enumerate OctoMY test projects</div><div> <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7e67b8; color: #45818e;">OctoMYTestProbe</span></b> {</div><div> id: octomyTests</div><div> searchPath: testDir</div><div> }</div><div> references: octomyTests.testFiles.concat([commonTestDir])</div><div>}</div></div><div><br /></div><div><br /></div><div>As you can clearly see, this is also a project. Since it is referred to by the top-level project it is in fact a sub-project, and you can see that the name it will display in QtCreator is "Tests".</div><div><br /></div><div>Further you can see that it has some notable properties:</div><div><ul><li><b>srcDir</b></li><li><b>projectDir</b></li><li><b>testDir</b></li><li><b>commonTestDir</b></li><li><b>commonTestLib</b></li></ul><div>These are set using JavaScript expressions that use the Qbs FileInfo service. Qbs has <a href="https://doc.qt.io/qbs/list-of-builtin-services.html">many services</a> or libraries with functions that help us with all kinds of things ranging from file and string manipulation to getting information about the platform.</div></div><div><br /></div><div>Next we see a new item called <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7e67b8; color: #45818e;">OctoMYTestProbe</span></b>. You might have put two together already and realized where this was defined. In our main project file we used a property called <b>qbsSearchPaths</b> to ask Qbs to look for our user defined re-usable components. In that folder there was an item called <span data-darkreader-inline-color="" style="--darkreader-inline-color: #7e67b8; color: #45818e;"><b>OctoMYTestProbe.qbs</b></span> that Qbs now conveniently has loaded and made available to us.</div><div><br /></div><div><i>NOTE: components are only made available in files referred to by the main project for technical reasons. This is one of many reasons why it is a good idea to separate your Qbs project into multiple files, for all but the smalest of projects.</i></div><div><br /></div><div>Qbs has a concept of <b>Probes</b>. The job of a <a href="https://doc.qt.io/qbs/qml-qbslanguageitems-probe.html">probe</a> is to look for things or perform expensive calculations. Probes are executed before the build starts and Qbs has some clever caching mechanisms that ensure they are only executed once. If you are doing anything intense, be it search through folders, calculate hashes or whatever else, Probes are your best friend. Probes also promote code re-use.</div><div><br /></div><div>Our <b style="color: #45818e;">OctoMYTestProbe.qbs </b>probe looks like this:</div><div><br /></div><div><div>import qbs.File</div><div>import qbs.FileInfo</div><div><br /></div><div>Probe{</div><div> // Parameters</div><div> property string name: "OctoMYTestProbe"</div><div> property string searchPath: FileInfo.cleanPath(FileInfo.joinPaths(project.sourceDirectory, "test")) + FileInfo.pathSeparator()</div><div> property string testFileName: "test.qbs"</div><div> property string testDefinePrefix: "OC_USE_TEST_"</div><div> property string commonTestDir: FileInfo.cleanPath(FileInfo.joinPaths(searchPath, "common_test")) + FileInfo.pathSeparator()</div><div> // Outputs</div><div> property stringList testNames: []</div><div> property stringList testFolders: []</div><div> property stringList testFiles: []</div><div> property stringList testDefines: []</div><div> configure: {</div><div> found=false;</div><div> var raw = File.directoryEntries(searchPath, File.Dirs | File.NoDot | File.NoDotDot);</div><div> <b>testNames</b> = (raw || []).filter(function(dir){</div><div> if(testFileName){</div><div> return dir.startsWith("test") && File.exists(FileInfo.joinPaths(searchPath, dir, testFileName));</div><div> }</div><div> else{</div><div> return dir.startsWith("test");</div><div> }</div><div> });</div><div> <b>testFolders</b> = testNames.map(function(testName){</div><div> return FileInfo.joinPaths(searchPath, testName);</div><div> })</div><div> <b>testFiles</b> = testFolders.map(function(testFolder){</div><div> return FileInfo.joinPaths(testFolder, testFileName);</div><div> })</div><div> <b>testDefines</b> = testNames.map(function(testName){</div><div> return testDefinePrefix + testName.toUpperCase();</div><div> })</div><div> found = testNames.length > 0;</div><div> console.info("Probing returned for '" + name+"':");</div><div> console.info(" + found="+found);</div><div> console.info(" + searchPath="+JSON.stringify(searchPath, null, "\t"));</div><div> console.info(" + testNames="+JSON.stringify(testNames, null, "\t"));</div><div> console.info(" + testFolders="+JSON.stringify(testFolders, null, "\t"));</div><div> console.info(" + testFiles="+JSON.stringify(testFiles, null, "\t"));</div><div> }</div><div>}</div></div><div><br /></div><div>As you can see, the probe uses the <a href="https://doc.qt.io/qbs/jsextension-file.html">File service</a> to look for directories beginning with "test" that contains a file called "test.qbs".</div><div><br /></div><div>It sets the special property <i><a href="https://doc.qt.io/qbs/qml-qbslanguageitems-probe.html#found-prop">found</a></i> to true if the number of folders found is more than zero.</div><div><br /></div><div>It also logs a bunch of stuff to the console.</div><div><br /></div><div>Qbs Supports printing of debug strings to the console using console.info() which can be very useful while debugging.</div><div><br /></div><div>The probe will be ran and produce some useful properties for us:</div><div><ul><li><b>testNames</b> - a list of the names of tests found in our project</li><li><b>testFolders</b> - the folders for each of our tests</li><li><b>testFiles</b> - the test.qbs file for each test</li><li><b>testDefines</b> - some defines that refer to our test names</li></ul><div>Now when we go back to test/<b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">tests.qbs</span></b> and have a closer look, we will see this:</div></div><div><div><br /></div><div>...</div><div><div> <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7e67b8; color: #45818e;">OctoMYTestProbe</span></b> {</div><div> id: <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ff1afe; color: #ff00fe;">octomyTests</span></b></div><div> searchPath: testDir</div><div> }</div><div> references: <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ff1afe; color: #ff00fe;">octomyTests</span></b>.<b>testFiles</b>.concat([commonTestDir])</div><div>...</div></div></div><div><br /></div><div>As you can tell, we are making an instance of the <b><span style="color: #45818e;">OctoMYTestProbe</span></b> called <b><span style="color: #ff00fe;">octomyTests</span></b>, and we pass the calcualted property <b>testFiles</b>, which is a list of qbs files, one for each test, to the references. In other words, we are telling Qbs to read in all these test project qbs files as part of the Test project. In QtCreator you will see that it genereates a full list of tests in the project tree.</div><div><br /></div><div>So why did we go to all this trouble instead of just naming the tests manually in a list?</div><div><br /></div><div>Well, now we never have to change this project file again. Whenever we create a new test, it will magically appear thanks to our clever Probe🎉.</div><div><br /></div><div><br /></div><div><div><div>This concludes the <a href="http://blog.octomy.org/search/label/qbs-tutorial">second part in a series</a> on using <a href="https://qbs.io/">Qbs</a> to our benefit and joy in a non-trivial project, namely <a href="http://www.octomy.org/">OctoMY™</a></div><div><br /></div></div><div>In the <a href="http://blog.octomy.org/2023/02/qbs-tutorial-part-35-libraries.html">next part</a> we will look at src/<b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">libs.qbs</span></b> and how it relates to the main project file.</div><div><br /></div><div>Illustrations borrowed from the amazing collection at <a href="https://ericjoyner.com/">https://ericjoyner.com/</a></div><div><br /></div></div>OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-32295810113689630212023-02-24T01:00:00.003+01:002023-02-24T03:53:57.456+01:00Qbs tutorial part 1/5: Main project file<p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEi0ji52sAzrdJeFgR8BFbrtBo5e184hIUbXiXBfRs6LInPPE127cusQZDTO67pPcW0kSCZySAUhEdjgbOEYStVfBuUBrtSSpFZcXL_7yirfj7-_EBaVZnhRWV5AJGVF8BospCq6OK3TvLGj146wfvOvfCFWQvaCpKI1jqZkU2QPhvGOVv2wX4zTsd7-6Q" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="727" data-original-width="1000" height="291" src="https://blogger.googleusercontent.com/img/a/AVvXsEi0ji52sAzrdJeFgR8BFbrtBo5e184hIUbXiXBfRs6LInPPE127cusQZDTO67pPcW0kSCZySAUhEdjgbOEYStVfBuUBrtSSpFZcXL_7yirfj7-_EBaVZnhRWV5AJGVF8BospCq6OK3TvLGj146wfvOvfCFWQvaCpKI1jqZkU2QPhvGOVv2wX4zTsd7-6Q=w400-h291" width="400" /></a></div><br /><br /><p></p><p>After spending a few gruelling weeks porting my brain to "think in Qbs", I felt ready to take on the non-trivial task of <a href="http://blog.octomy.org/2023/02/octomy-will-migrate-from-qmake-to-qbs.html">comitting 100% to porting the build system of OctoMY™ from qmake to Qbs</a>. This was in large part possible thanks to the super-human patience and wisdom demonstrated by the <a href="https://discord.gg/M7vV5BC2" target="_blank">super awesome Qbs community, which lives on Discord</a>. Shoutout to ABBAPOH, Psy-Kai and Janet Blackquill, your help was indispensible!</p><p>I thought I would document my decisions here for future reference and maybe to serve as a template for others trying to get into Qbs with their non-trivial projects. I will also introduce some concepts and tips & tricks that I picked up along the way.</p><p>So first up: top level project structure. OctoMY™ is divided coarsely into 3 parts:</p><p></p><ul style="text-align: left;"><li><i>Apps</i> - The actual programs that we run when we want to use OctoMY™</li><li><i>Libs</i> - The software components which contains the code of OctoMY™, liked into the apps</li><li><i>Tests</i> - A bunch of programs, each testing one aspect of the codebase</li></ul><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgm4Zhv9IVHageWFvjwvoRpIokbLwHT6nckHLsuvj2P6UBBEAZtT2lZbHe20MIYUMllpHavEa4X2_cQ0IR0MoQo_yXYL4R8D42bwn8jMLVI6iDJ26KiZ2rYfLsoJ1lXOS0G7x5Kd6BXpNZhFEFBxA74zvuTyFkACcJxajM7sv06oUXm62h7NCjiX-jNkA/s1000/The-Mountaineers.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="683" data-original-width="1000" height="274" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgm4Zhv9IVHageWFvjwvoRpIokbLwHT6nckHLsuvj2P6UBBEAZtT2lZbHe20MIYUMllpHavEa4X2_cQ0IR0MoQo_yXYL4R8D42bwn8jMLVI6iDJ26KiZ2rYfLsoJ1lXOS0G7x5Kd6BXpNZhFEFBxA74zvuTyFkACcJxajM7sv06oUXm62h7NCjiX-jNkA/w400-h274/The-Mountaineers.jpg" title="The three parts of the project" width="400" /></a></div><br /><div><br /></div><div>The file structure of the project looks like this:</div><div>.</div><div><div>├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ff1a1a; color: red;">OctoMY.qbs</span></b></div><div>├── src</div><div>│ ├── agent</div><div>│ │ ├── AgentMain.cpp</div><div>│ │ ├── AgentMain.hpp</div><div>│ │ ├── <span data-darkreader-inline-color="" style="--darkreader-inline-color: #1dff1a; color: #04ff00;"><b>app.qbs</b></span></div><div>│ │ └── README.md</div><div>│ ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">apps.qbs</span></b></div><div>│ ├── combined</div><div>│ │ └── lib.qbs</div><div>│ ├── libs</div><div>│ │ ├── libagent</div><div>│ │ │ ├── agent</div><div>│ │ │ │ ├── Agent.cpp</div><div>│ │ │ │ ├── Agent.hpp</div><div>│ │ │ │ └── AgentWindow.ui</div><div>│ │ │ ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #411aff; color: #2b00fe;">lib.qbs</span></b></div><div>│ │ │ └── README.md</div><div>│ ├── <span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;"><b>libs.qbs</b></span></div><div>├── test</div><div>│ ├── common_test</div><div>│ │ ├── Common_test.hpp</div><div>│ │ ├── CommsTester.cpp</div><div>│ │ ├── CommsTester.hpp</div><div>│ │ ├── mock</div><div>│ │ │ ├── MockCourier.cpp</div><div>│ │ │ └── MockCourier.hpp</div><div>│ │ ├── resources</div><div>│ │ │ ├── icons</div><div>│ │ │ │ ├── profile.svg</div><div>│ │ │ │ ├── stress.svg</div><div>│ │ │ │ └── test.svg</div><div>│ │ │ └── test_resources.qrc</div><div>│ │ ├── Utility_test.cpp</div><div>│ │ └── Utility_test.hpp</div><div>│ ├── testLogHandler</div><div>│ │ ├── TestLogHandler.cpp</div><div>│ │ ├── TestLogHandler.hpp</div><div>│ │ └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #1affff; color: #01ffff;">test.qbs</span></b></div><div>│ ├── testTryToggle</div><div>│ │ ├── TestTryToggle.cpp</div><div>│ │ ├── TestTryToggle.hpp</div><div>│ │ └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #1affff; color: #01ffff;">test.qbs</span></b></div><div>│ └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">tests.qbs</span></b></div><div>└── integration</div><div> └── <b>qbs</b></div><div> └── imports</div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7fb767; color: #6aa84f;">OctoMYApp.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7fb767; color: #6aa84f;">OctoMYLibProbe.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7e67b8; color: #674ea7;">OctoMYAutoLib.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7e67b8; color: #45818e;">OctoMYTestProbe.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #79b2be; color: #45818e;">OctoMYAutoTest.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYFiles.qbs</span></b></div><div> ├── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">OctoMYQtDepends.qbs</span></b></div><div> └── <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #b96890; color: #a64d79;">utils.js</span></b></div></div><p></p><div>So there is a lot to cover here, and I promise that we will go over one part at the time so that it will all make sense in the end!</div><div><br /></div><div>First, qbs consist of strategically placed text files with the <i>.qbs</i> file extension. Inside these qbs files is a declarative syntax borrowed from <a href="https://doc.qt.io/qt-6/qmlapplications.html">QML</a>. Expect to see a bunch of json-like blocks of data with some javascript sprinkled on top.</div><div><br /></div><div>The top-level file of the project is <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ff1a1a; color: red;">OctoMY.qbs </span></b>This marks the entrypoint for qbs, and it is this file which qbs will read first, and this is the file you open in QtCreator to load the project.</div><div><br /></div><div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgEL6JRy2ELIOvw8LRtUUBvXwAHHNrGHiLFNdo5yMPWZfmzeTD_BMXVimJ6zu0TbZyMNJ3YdgVI0EcMLtP-821A-jADIwv0YfcgKQ70i2l2lWzjnCNI_IuhneZMz_Fp-zIQVyQEPyiNjHq4LV9FNeg6iXeWJlrEmPOdIk_8twycVxEUvm0kLFdlDAhG5g" style="margin-left: auto; margin-right: auto;"><img alt="" data-original-height="282" data-original-width="282" height="400" src="https://blogger.googleusercontent.com/img/a/AVvXsEgEL6JRy2ELIOvw8LRtUUBvXwAHHNrGHiLFNdo5yMPWZfmzeTD_BMXVimJ6zu0TbZyMNJ3YdgVI0EcMLtP-821A-jADIwv0YfcgKQ70i2l2lWzjnCNI_IuhneZMz_Fp-zIQVyQEPyiNjHq4LV9FNeg6iXeWJlrEmPOdIk_8twycVxEUvm0kLFdlDAhG5g=w400-h400" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Qbs project in QtCreator<br /></td></tr></tbody></table><br /><br /></div><div><br /></div><div>As you can see, I have used color coding thoruhgt this article so that you may easily see the link between views. For example, the main project file has been marked <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ff1a1a; color: red;">red</span></b>, and the sub-project files that it references <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">yellow</span></b> in this entire article, so you can readily find them in the file structure above.</div><div><br /></div><div><br /></div><div><b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ff1a1a; color: red;">OctoMY.qbs </span></b>looks like this:</div><div><br /></div><div><br /></div><div><div>import qbs.FileInfo</div><div><br /></div><div>Project {</div><div> name: "OctoMY™"</div><div> qbsSearchPaths: [ FileInfo.joinPaths(path, "integration", "<b>qbs</b>") + FileInfo.pathSeparator()]</div><div> references: [</div><div> "src/<span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;"><b>libs.qbs</b></span>"</div><div> , "src/<b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">apps.qbs</span></b>"</div><div> , "test/<b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">tests.qbs</span></b>"</div><div> ]</div><div>}</div></div><div><br /></div><div><br /></div><div>As you can see, it has some important lines:</div><div><br /></div><div><ul style="text-align: left;"><li><b>import qbs.FileInfo</b>: This is how we get access to other types and script libraries in qbs. In this case, we need the <a href="https://doc.qt.io/qbs/jsextension-fileinfo.html">FileInfo service</a> provided with qbs that allows us to do file operations.</li><li><b>Project</b>: This indicates that we are defining a new qbs project. "Project" is a qbs type that represents a project. It is used to collect other items inside of it similar to a folder in a filesystem. It can contain other items directly inside of it, or it can refer to files which in turn will contain such items. In our case we only refer to other files through the references property (see below).</li><li><b>name</b>: This is what shows up inside QtCreator as the name of your project. If you leave it out, Qbs will use the file as a fallback. In other words, this property is optional.</li><li><b>qbsSearchPaths</b>: This points to where qbs will look for our user defined reusable components, of which there are several in the OctoMY™ project. You don't have to use this feature, but it will serve you well to use it once your Qbs project grows beyond the trivial "Hello World" examples. In this case we tell qbs that this project will look for our components in ./integrations/<b>qbs</b> folder, and you can see (in theproject tree at the top of this article) that it contains some components that we will use from sub projects, such as <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #7e67b8; color: #45818e;">OctoMYTestProbe.qbs</span></b>.</li><li><b>references</b>: References is a list of files that Qbs should read and include in the project. Since we are currently defining a project, we want to include the actual sources and libraries and tests of the project, and that is done by referring to the qbs files which we use to find them. In this case we include 3 sub-projects via the <b><span style="color: #ffa400;">libs.qbs</span></b>, <b><span style="color: #ffa400;">apps.qbs</span></b> and <b><span style="color: #ffa400;">test.qbs</span></b> files.<br /></li></ul>As you can see, I have color coded some files such as the main project file in <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ff1a1a; color: red;">red</span></b>, and the sub-project files that it references in <b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">yellow</span></b> in this entire article series, and so you can readily find them in the file structure.</div><div><br /></div><div>This concludes the <a href="http://blog.octomy.org/search/label/qbs-tutorial">first part in a series</a> on using <a href="https://qbs.io/">Qbs</a> to our benefit and joy in a non-trivial project, namely <a href="http://www.octomy.org/">OctoMY™</a></div><div><br /></div><div>In the <a href="http://blog.octomy.org/2023/02/tests-in-last-part-we-looked-at-overal.html">next part</a> we will look at test/<b><span data-darkreader-inline-color="" style="--darkreader-inline-color: #ffad1a; color: #ffa400;">tests.qbs</span></b> and how it relates to the main project file.</div><div><br /></div><div><br /></div><div>Illustrations borrowed from the amazing collection at <a href="https://ericjoyner.com/">https://ericjoyner.com/</a></div>OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-78328162920351365032023-02-24T00:30:00.000+01:002023-02-24T03:45:37.446+01:00OctoMY™ will migrate from qmake to Qbs<p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjVRDU32VUEGwMcCB5Dqbc-2XopP9VHw3f7qzIKpWtLkGlFj4O-yaCo63Wig3iv_EcEStE27VhNoZpA9TmmqfVqyTgHtmuXgNQs4UsYUmSUvFEm_GiLVnPpkwwNhVgNtX_CuoU8BYJQhjayPAl8wCIzHwjZP4v0YQ3HEYesZV-1WDWOCT5s16aHjXasSg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="750" data-original-width="1000" height="300" src="https://blogger.googleusercontent.com/img/a/AVvXsEiDSR9ozPVW54m20Db2YhG2YZBbT-UHJSluzXq9LYiQqSqoiK2nZ1o_rkZP-5GnnqlgX0EGiwk3d-5wu0PPgh8YBAb3lgu-jJpgsCZtKdqtDYl7vV_wSO0ZA0AvPc4eKvvNHY8hsqTn9-i8-kgOBTjOhS6ZEDz43ogs66gNapbk5KMyubx7bML08es5LQ=w400-h300" width="400" /></a></div></div></div><p>OctoMY™ has from this date forward decided to standardize on Qbs and migrate from qmake to Qbs. qmake project files will remain for some time until we see that the Qbs project files replace them perfectly before they will be removed. Thanks for all the fish qmake!</p><p><br /></p><p>This might seem like a strange decision since <a href="https://www.qt.io/blog/qt-and-cmake-the-past-the-present-and-the-future">Qt itself has selected CMake in favor of their own Qbs</a> project, however the benefits Qbs will have to OctoMY™ is substancial compared to what CMake will bring. So here is the list of reasons why OctoMY™ will chose Qbs over CMake:</p><p></p><p></p><ul style="text-align: left;"><li>CMake is arguably hard to work with, inelegant, cargo-culty, full of legacy, slow, inflexible, archaic and <a href="https://www.reddit.com/r/cpp/comments/qum4sq/whats_the_hate_for_cmake_all_about_is_cmake/">challenging to like</a></li><li>The main selling point of CMake is that "everyone is using it" and so you will find that a lot of projects support CMake and consuming these projects as dependencies with CMake will be simpler. This is however <i>not relevant for OctoMY™</i> because we have a strict policy of not depending on any external libraries except Qt framework itself. All the sources are in the tree.</li><li>CMake will allow us to export our project as a dependency to others. Again, this is a mute point as OctoMY™ will not be consumed as a source level dependency.</li><li>Qbs is well supported by Qt (they developed it after all)</li><li>Qbs is well integrated into QtCreator which is very important for OctoMY™ since we depend on that as our main development tool</li><li>Qbs is modern</li><li>Qbs is flexible</li><li>Qbs is fast</li><li>Qbs is multi-platform and has good support for all the platforms that OctoMY™ do and will need support for in the future</li><li>Qbs is open-source</li><li>Qbs is well written (if you peek inside the sources of Qbs, you will probably like what you see)</li><li>Qbs acts as a server that talks to QtCreator over a pipe. This means that QtCreator will better reflect the internal state of Qbs at any given time. For example, it would automatically update the project tree view in QtCreator whenever I saved changes to the project (*.qbs) files, and Qbs would act as expected in many cases where qmake just would not. This gave a surprisingly fluid experience that is addictive.</li><li>Qbs really maxes out your CPU at build time and spends almost zero time on house-keeping. The system is really fast at dependency checking and re-building only the necessary files making your developer experience quite pleasant.</li><li>It has not yet screwed up dependencies even once even in my very demanding project and with me as a demanding user which is quite impressive. qmake would require a full re-build on a regular basis.</li><li>While Qbs works out of the box with Qt, it is not limited to Qt. It has extensions to support a whole load of platforms, languages and frameworks and can integrate with a bunch of developer tools including IDEs, other build tools and more. Especially, Qbs aims to tackle the not-for-the-faint-of-heart builds that target embedded hardware, mobile platforms and other quirky and archaic targets full of demanding requirements such as cross compilation and advanced tool-chain management. Impressive! This means we have some wiggle-room for futer expansion of the OctoMY™ project</li><li>There is a <a href="https://discord.gg/M7vV5BC2">Qbs Discord Server</a> where devs and users of Qbs hang out. This has been one of the best discoveries so far. The amount of patience and wisdom the core team have showed me as a annoying beginner is truely amazing.</li><li>Qbs will hopefully grow and get a much deserved boost in adoption!</li></ul><div><br /></div><div>Qbs is not perfect, and here are a few of the things that I did NOT like so far:</div><div><ul style="text-align: left;"><li>The Qbs output is very sparse and debugging Qbs is very difficult for a beginner in the start before you start udnerstanding how it all works under the hood. The log output windows in QtCreator will all just be completely empty even if there definitely are some problems. There are options to add more verbose output, but it is well hidden and off by default. Also the "max verbose" option is not possible to swithc on at all.</li><li>"printf debugging" is hard since Qbs is declarative. It is definitely possible but very quirky.</li><li>Some of the features in Qbs have severe pitfalls that you are expected to pick up on by yourself. Here are some examples:</li><ul><li>Group prefix is a string, and NOT a file entity. In other words, "someFolder" and "someFolder/" means different things.</li></ul><li>While the documentation is "complete" it is kind of sparse still, and leaves you wondering about implementation details in many cases. For example, does Group.excludeFiles support wildcards like Group.files or not? (The answer is yes, it does, but the documentation does not mention this).</li></ul><div>All these downside however, are easy to fix, while arguably the downsides of CMake are not at all easy to fix.</div></div><div><br /></div><div><br /></div><p></p>OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-39850138037650768152023-02-07T13:22:00.003+01:002023-02-07T13:22:47.524+01:00Old dog learns new tricks: Qbs edition<p>So I had a go at QML a few years ago and it seems like a cool technology and definitely has a lot of potential for creating good user interfaces.</p><p>Getting started with QML is easy enough thanks to the examples directly present in QtCreator. You can get up and running quickly and adapt an example to what you want to achieve.</p><p>After a while you will stumble upon a bunch of more or less fundamental questions like:</p><p></p><ul style="text-align: left;"><li>How can I interface QML with my existing C++ code?</li><li>How can I get the filename and path of the current module from code?</li><li>What is the meaning of life?</li></ul><div>Most of these questions are sort of answered in the examples or in the documentation.</div><div><br /></div><div>So I thought I had enough QML under my belt to tackle Qbs, the misunderstood, does everything right-yet-nobody-uses-it build system invented by Qt.</div><div><br /></div><div>Qbs lives on it's own domain, has minimalist examples and documentation and seems to be completely neglected by the whole world. But it is using QML under the hood so that is a start.</div><div><br /></div><div>Or so I thought.</div><div><br /></div><div>It could very well be me whom is the problem here. After all I am an old fart that has been too long in the industry. I used to joke that "I learned to program before the internet" which is technically true.</div><div><br /></div><div>But for some reason getting into Qbs has left me feeling extra old. It feels as if there is a great secret that everyone knows except me. But I won't shy away from a good challenge and so I have decided to conquer Qbs before I make my judgement. My hope is that all the promise it holds will be unleashed upon my projects once I unlock it's secrets.</div><div><br /></div><div>The journey begins!</div><div><br /></div><div><br /></div><p></p>OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-62628308677003331322023-02-02T05:29:00.005+01:002023-02-02T05:29:25.155+01:00Brief OctoMY™ update 2023<p>These are the changes scheduled for early to mid 2023 in the OctoMY™ project:</p><p></p><ul style="text-align: left;"><li>Good bye Qt5 hello Qt6</li><li>Refactoring of subsystems relating to media such as speech, video streaming etc</li><li>Once-over of whole project</li><li>New build system</li></ul><p></p><h2 style="text-align: left;">Good bye Qt5 hello Qt6</h2><div>Perhaps a little overdue, we finally support Qt6. Since we didn't really have a usable build in Qt5, we have just put that behind us and we are going all inn on Q6.</div><h2 style="text-align: left;">Media subsystem</h2><div>This derives partly from the Qt6 transition as Qt6 introduced many changes in the underlying media related APIs and partly from the initial implementations in OctoMY™ showing it's age as many were the first parts of the codebase to be implemented and they have suffered from systemic neglect ever since.</div><h2 style="text-align: left;">Once-over</h2><div>With a Qt version update and lots of refactoring there is always a risk of introducing lots of healthy little bugs, so this step means simply looking it over and adding tests where they are needed, running all the parts of the oprogram to see if any bugs show up.</div><h2 style="text-align: left;">New build system<br /></h2><div>With Qt6 came the astonishingly pragmatic (near-sighted?) decision by Qt project to move Qt away from qmake and on to CMake. The first part I completely understand, while I have learned to love qmake it still is a flawed little program and not really feasible for a large project such as Qt.</div><div><br /></div><div>The second part of the decision; to transition to CMake feels like substituting pest for cholera. Time will tell if this was a great idea, especialkly since they had an alternative at their hands that shows a lot of rpomise as a proper next generation alternative, namely Qbs.</div><div><br /></div><div>OctoMY™ project has some build needs that are difficult to express in either build system (being able to not maintain lists of files that are part of the project up front, and being able to dynamically chose wether a library should be linked separately or not) so we will look at adopting Qbs. So far it seems it will suit OctoMY™ quite nicely.</div><div><div><div><br /></div></div></div>OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-36249107042559998122023-01-31T04:20:00.009+01:002023-01-31T04:35:10.117+01:00My pet peeves with Qt and QtCreator in 2023<p>I took a break from C++ and Qt for a few years as I was working on other stuff, and when I came back a unique opportunity presented itself; I could look at Qt from an outsider's perspective not being as biased as before. Well I am biased, Qt is my all time favorite platform so who am I kidding. But I have seen the world beyond and just <i>maybe</i> I can spot some trends where Qt moved while I was gone? This is in essence my mandatory rant on UX in programming tools, with Qt & QtCreator as a backdrop.</p><p><i>NOTE: I am looking at this from a community perspective. I am sure if you pay for Qt your experience will differ in some respects.</i></p><h2 style="text-align: left;">Installation</h2><p>Installing Qt is still terrible, but a little better than it used to be. It still features an install wizard straight from the 1990s era, but at least it has green color to bring it into the future.</p><p><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj1vq9kdFjvKAYmr7USYItkamnAxJaRUhJMLqJZFX_-HCdBWxvtAURyUhYHE8vd--ddLxMMRrKgT9P6_j8FwnHb_lvJXNwik2tb1mqhIz1sfdGCQdOR1PqpFCfYajIW4GbYTscRXRWeBMBGLfotIMNwvmeVa8AOQkhFKBYwfiwFPeQMKybSgXeTKxC4ig" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="" data-original-height="200" data-original-width="252" height="318" src="https://blogger.googleusercontent.com/img/a/AVvXsEj1vq9kdFjvKAYmr7USYItkamnAxJaRUhJMLqJZFX_-HCdBWxvtAURyUhYHE8vd--ddLxMMRrKgT9P6_j8FwnHb_lvJXNwik2tb1mqhIz1sfdGCQdOR1PqpFCfYajIW4GbYTscRXRWeBMBGLfotIMNwvmeVa8AOQkhFKBYwfiwFPeQMKybSgXeTKxC4ig=w400-h318" width="400" /></a></p><p>Seriously, the wasted potential is staggering. I wish someone would appoint me UX lead on the installer team, I would have a go at setting things straight. Seriously, <a href="https://www.vevstolen.no/contact">get in touch</a>! I will let the real-time html layout popping go I promise!</p><p>To be fair here are the options:</p><p></p><ol style="text-align: left;"><li>Install ancient mangled version from your favorite Linux distro's repository (not recommended)</li><li>Build from source.</li><ol><li>Just rememer to schedule 20 minutes of your time to actually find the download link on the qt.io website. This is what happens when the marketing people takes over. I mean they really tore a page from the the old <a href="https://en.wikipedia.org/wiki/Fear,_uncertainty,_and_doubt">Microsoft 1990s era FUD tactic</a> playbook here. The only contender is the delete account wizard in the Boo dating app.</li><li>Once you have the source.... uhm. ok so yes. I will... follow these steps and. Uhm.. <i>It is almost as if someone made it extra hard on purpose</i>.</li></ol><li>Use some 3rd party Docker image that encapsualtes the build. Because there are no official ones. Seriously, <i>Qt company has no official Docker images to use their shit in 2023</i>.</li><li>Download online installer:</li><ol><li>On linux; a payloaded bash script with a windows style install wizard inside.</li><li>On OSX; an img with a windows style wizard inside.</li><li>On Windows; a native executable with a windows style wizard inside.</li><li>The wizard has the worst UX of any installer I have ever used, and I have used alot of installers in my lifetime. It is actually inexcusable.</li></ol><li>Download offline installer:</li><ol><li>Nope, can't find it anymore. Is it there? Well you did a good job hiding it. PEBCAK.</li></ol><li>Download prebuilt binaries in ZIP format.</li><ol><li>I don't know if they even exist because all the files are so well hidden. If the actually exist then I am sorry for being a retard. PEBCAK.</li></ol></ol><p></p><h2 style="text-align: left;">Migration to Qt6</h2><p>Migrating from Qt5 to Qt6 in my projects was actually not that bad. It took a day of search/replace/copy/paste for a fairly large codebase. Luckily I had lot's of tests to verify my changes but still the experience was good overal. QRegularExpression and QMedia* were the most hard to adapt.</p><p><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjxlNRGUdnalabeQQcQvNnh0zWc9UMzNynah1z1oqD_MKtsXRPEBOwHdHunzyhwuHJ6njYmf6l72rUEVYyncRsXY-uboBBm8wj0-fzKlJJMVP3iPGUFModHDD7Eod37q5v4MRE668XiJGXbNjM3df4urzV13eAlX8yaQ-IRH0LvNA5sCzV3tRoMpJOkig" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="" data-original-height="218" data-original-width="600" height="145" src="https://blogger.googleusercontent.com/img/a/AVvXsEjxlNRGUdnalabeQQcQvNnh0zWc9UMzNynah1z1oqD_MKtsXRPEBOwHdHunzyhwuHJ6njYmf6l72rUEVYyncRsXY-uboBBm8wj0-fzKlJJMVP3iPGUFModHDD7Eod37q5v4MRE668XiJGXbNjM3df4urzV13eAlX8yaQ-IRH0LvNA5sCzV3tRoMpJOkig=w400-h145" width="400" /></a></p><p>The documentation spesific to migration was OK, but it could definitely have been much better. I would have loved to see a dropdown at the top of documentation pages where you could select the version you care about instead of fumbling around with google to find the relevant version. Also a collapsed comment on migration next to each deprecated member would be really helpful, instead of having all migration stuff collected on one big page.</p><p>Good documentation is one of the best sides of Qt so not complaining too much here!</p><h2 style="text-align: left;">CMake</h2><p>CMake? SERIOUSLY?</p><p>I know this is a controversial topic. A lot of people like CMake, and a large minority dislike it. And I have a fairly strong opinion myself. Here is my breakdown;</p><p>I think that the people that like CMake <i>like it for a completely different reason than why the other people dislike it</i>. The people that like CMake are very <b>pragmatic</b>. They made it work with CMake and then it works and now we can go do something else. Or they were told by their non-technical boss to use CMake beacuse "customer X uses CMake and we must align with them".</p><p>The people that don't like CMake are more <b>opportunistic</b> and <b>perfectionistic</b>. I suspect there is a good overlap in this group with those that liked Qbs for this reason. They just can't look at CMake next to Qbs or qmake and think that CMake is the better choice. This group think (and I agree with them) while the rest of industry selected CMake, that alone is <b>not a good enough argument to use it</b>. Instead we should strive to surpass it on every metric beyond "popularity by mediocre middle managers" (to put it on point).</p><p><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhRcxTsC3NgmvjejtZOhKYulmYVz1gbgEUG4h1HDdIB2Fl9nS2cHKm2uht8sf0ahRk_4ojWNdft3IUWT7m3XxPGHUqh-ukjwZOmVN-SpimWQG4DOat8rzDhxKubpLZUK25evJtVlavwNPp0FN-_W7NMhNpysMHPbrZNBoodTrA8KLm0qYjgD-mOgZDtng" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="" data-original-height="383" data-original-width="651" height="235" src="https://blogger.googleusercontent.com/img/a/AVvXsEhRcxTsC3NgmvjejtZOhKYulmYVz1gbgEUG4h1HDdIB2Fl9nS2cHKm2uht8sf0ahRk_4ojWNdft3IUWT7m3XxPGHUqh-ukjwZOmVN-SpimWQG4DOat8rzDhxKubpLZUK25evJtVlavwNPp0FN-_W7NMhNpysMHPbrZNBoodTrA8KLm0qYjgD-mOgZDtng=w400-h235" width="400" /></a></p>OctoMY™ is currently on a semi-hacked qmake setup that works great, but we are looking at Qbs to see if that could be even better. For OctoMY™ CMake isn't even remotely on the radar.<p></p><h2 style="text-align: left;">File types support</h2><div>I don't know if this is just my memory failing me, but I definitely can't remember that there was this good support for non-Qt related filetypes like Dockerfiles, .dockerignore, *.py, *.js, *.sh, *.md and so on. After a quick highligter update they all seem to highlight beautifullty and support normal indentation. <b>Good job</b>!</div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjSdboWgF4WfDH-y29Yk6H2GjR-rGithrhVr6G-DlSx2XTNtvP9m8-KFEZG_adRkAi4gdBr8-UR68d0XS1f3Ow-frIfUBCPFYbQPFTyWUHUTOy4WpLMsTDFZ7XWh3rmkYEv_of0TL8JwYbUATdp3hw47l6Ey6LM6DMHurIeuxVmEsT1ZgCos51WBwVdmQ" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="" data-original-height="538" data-original-width="800" height="269" src="https://blogger.googleusercontent.com/img/a/AVvXsEjSdboWgF4WfDH-y29Yk6H2GjR-rGithrhVr6G-DlSx2XTNtvP9m8-KFEZG_adRkAi4gdBr8-UR68d0XS1f3Ow-frIfUBCPFYbQPFTyWUHUTOy4WpLMsTDFZ7XWh3rmkYEv_of0TL8JwYbUATdp3hw47l6Ey6LM6DMHurIeuxVmEsT1ZgCos51WBwVdmQ=w400-h269" width="400" /></a></div><div><br /></div><h2 style="text-align: left;">File Operations</h2><div><p>This peeve goes way back. Unfortunately it has worsened over time. It has several facets. I will start with the most annoying and obvious for me.</p></div><div>QtCreator is an <b>IDE</b>, which stands for <b>I</b>ntegrated <b>D</b>evelopment <b>E</b>nvironment. Why is it called that? Because in olden times we used to have a development cycle like this: </div><div><ol style="text-align: left;"><li>Open source in editor, make changes and save</li><li>Open terminal, invoke build command</li><li>Open debugger invoke program, debug, find error</li><li>Go back to editor make changes</li><li>Repeat</li></ol><div>And conversely, the IDE will allow you to do all this from within one program, thus being "integrated".</div></div><div><br /></div><div><b>QtCreator</b> delivers wonderfully on this workflow with only minor annoyances, so well done!</div><div><br /></div><div>However the IDE also must support other workflows that are very common in software development. Many of them are file related, for example:</div><div><br /></div><div><i>-- As a software developer, I want to add an existing file inside my project folder to the project</i></div><div><br /></div><div>or </div><div><br /></div><div><i>-- As a software developer, I want to move a file that is in a subfolder of my project into another folder</i></div><div><br /></div><div>If you take ANYTHING away from this blog post, please let it be this next sentence: <b>There really are a ton of small usecases in a developer tool that are deceivingly easy to ignore that will make or break the very essence of that tool.</b></div><div><b><br /></b></div><div><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjwf3ulkiRLaSnXMvBkO8zXYOUENYPRB1kGvFrjsVvATfZOfGj4FNtjn9CTpeg92fc-RJnpIcdCZCjpZvwdF9MlFvZOJUHjXdn0VVz82nqW_R6QhzyNjM6B8YVGTwFGvNWhvfpSHCbQ5qgpv-AsdQYWdee4mT7Je1_HRomJHrVEVzo4zR9tYEuQP0S3AA" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="" data-original-height="1080" data-original-width="1920" height="225" src="https://blogger.googleusercontent.com/img/a/AVvXsEjwf3ulkiRLaSnXMvBkO8zXYOUENYPRB1kGvFrjsVvATfZOfGj4FNtjn9CTpeg92fc-RJnpIcdCZCjpZvwdF9MlFvZOJUHjXdn0VVz82nqW_R6QhzyNjM6B8YVGTwFGvNWhvfpSHCbQ5qgpv-AsdQYWdee4mT7Je1_HRomJHrVEVzo4zR9tYEuQP0S3AA=w400-h225" width="400" /></a></div><div><br /></div><div>Does it have shiny beautiful icons? Does it load and save projects and files blistering fast? Does it look good on all supported platforms? All good and well. <i>But does it support the bread and butter daily file operations of a seasoned developer</i>?</div><div><br /></div><div>We don't want another shiny wizard. We want keyboard shortcuts, tricks and tips that work on a low level. Stuff that bear witness that the tool was made by ONE OF US. Example, it used to be that you could just rename a file in the tree view in QtCreator and use relative paths like so:</div><div><br /></div><div>"../newsubfolder/myfile.cpp" and it would magically understand what you meant; "move myfile.cpp from it's current location to newsubfolder". No need to bring up a menu, a bloated wizard, an external commandline or file manager.</div><div><br /></div><div>This disappeared at some point for unknown reason. And of course being able to just move the file with the mouse like normal human being is too much to ask so I won't ask it.</div><div><br /></div><h2 style="text-align: left;">Mandatory rant on UX in programming tools</h2><div><br /></div><div>If you read any good book on UX (like <a href="https://www.amazon.com/Dont-Make-Think-Revisited-Usability/dp/0321965515" target="_blank">Don't make me think</a>) it will certainly have a bias towards mass market appeal. What do I mean? I mean that it is part of UX syllabus and training that you should follow what the average user thinks and <b>focus on that exclusively</b>, remove everything else (yes actively removing it to avoid detraction of attention which is bad in UX).</div><div><br /></div><div>If you hire a hard working, well meaning, highly educated UX person straight from school with excellent grades she may very well demolish a good software developer tool because she will in the best case misread or worst case underestimate the users of that tool.</div><div><br /></div><div>In an IDE like QtCreator this is dangerous because we, the users, are a really smart bunch. The "average" C++ developer is not the one that benefits the company the most, it is the right side of the bell curve that will. Sure developer culture has transitions from being hero base to team based, but we all know a person or two that <a href="https://www.youtube.com/watch?v=-ltORkYAdVk">just are one step above the rest</a>. And the tools should NOT deter those team members!</div><div><br /></div><div>The sad part is that often it is the littel things, like the neat file-system hacks in the tree editor that nobody knows about. But JP the robot knows..</div><h2 style="text-align: left;">Media support</h2><div>In general the refactoring of media support in Qt6 seems level headed. However there is one use case that has not been addressed and it is super annoying:</div><div><br /></div><div><i>-- As a software developer, I want to convert a sequence of QImage into a video stream using only Qt (no external dependencies)</i></div><div><br /></div><div><a href="https://blogger.googleusercontent.com/img/a/AVvXsEis0lvn2un7Sf6I0LvpYAY3J3v4BsaqLpU3Om15XqAadE46J3yXvENwggvgg1Meiygr_vtbKgFC1MtlNYQ2_qUQwUF9BM-SLU319kW8K2Yk0R03oXZlzNeMhg8q08wkI1gM3y9gJxFsf_rHWH2qGhVjdIrmr5htQTaF1ri7Jiqr2LQdcbtBBgpoqg1Pvg" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="" data-original-height="566" data-original-width="800" height="283" src="https://blogger.googleusercontent.com/img/a/AVvXsEis0lvn2un7Sf6I0LvpYAY3J3v4BsaqLpU3Om15XqAadE46J3yXvENwggvgg1Meiygr_vtbKgFC1MtlNYQ2_qUQwUF9BM-SLU319kW8K2Yk0R03oXZlzNeMhg8q08wkI1gM3y9gJxFsf_rHWH2qGhVjdIrmr5htQTaF1ri7Jiqr2LQdcbtBBgpoqg1Pvg=w400-h283" width="400" /></a></div><div><br /></div><div>It is understood that this will be limited by the media codecs available on the platform, and maybe not be available on all platforms. But it is in my opinion essential for Qt to support this basic usecase.</div><div><br /></div><div>We are not all Steven Spielberg that crave the best 8k full format presentations. We just want to chuck these QImages into a video file and save it on youtube before calling it a day. It is 2023 after all. I don't want to werstle ffmpeg or libav into my project, that is why I use Qt, so I DON'T have to deal with platform spesific stuff. The annoying part is that Qt is so close! It already integration with the native media frameworks, so why can't they just add that 200 lines to support this out of the box?</div><p>I am not alone thinking about this, my question about <a href="https://stackoverflow.com/questions/38407128/how-to-generate-video-file-from-qimage-sequence-using-qmediarecorder-in-qt5-c" target="_blank">encoding video from a sequence of QImages</a> from 6 years ago has 63 votes and still no resolution.</p><h2 style="text-align: left;">Other annoyances</h2><p>Finally a list of minor anoyances in QtCreator that I felt needed to come of my chest after years of brooding.<br /></p><ol style="text-align: left;"><li>The refresh action is missing in the file tree so now I find myself closing and reopeng the program every time a file has changed outside QtCreator. Luckily closing and opening QtCreatos is now super fast for some reason. It feels really snappy, so good job on that at least...</li><li>The swap between source and header key combination is not <ctrl>+<tab> by default. C'mon guys.</li><li>There is no key combination for switching between design view and editor view, and for some inexplicable reason, I am always moved to look at my design in read-only XML. dafuq?</li><li>The editor view for design is READ ONLY? I have to open an external text editor to edit the XML for my design? SERIOUSLY? Why don't you just remove editor view entirely, and make it a special operation to edit for those rare cases when that is even remotely relevant? Am I the only one who is annoyed by this?</li><li>Design view still takes up the whole screen. On modern 4k displays this is a travesty, a UX abomination. The Designer editor should really present inside a normal editor view.</li><li>There is no "collapse all" and "uncollapse all" buttons in tree view. I have to dig thorugh a submenu. I might as well collaps and uncollaps the tree manually and it will be faster than finding those actions *sigh*.</li><li>There are still issues with scaling for high DPI screens. The issues view cannot be zoomed like the other views(??) and is sometimes displaying text in way too small font.</li><li>The "split side by side" is wonderful, however moving the separator is not intuitive. Expected is that "everything stays the same except the size of the two views next to the separator will change in size. Actual is "depending on which separator I move, SOME windows will stretch and other not". It should be super easy to fix, just remove the separator widget in place of a horizontal layout and add widgets to take mouse dragging to change the layout. Why is this not fixed ages ago?</li><li>It is sometimes desirable to view files that are NOT in your project in the tree view. Yes I know, radical thought. How about adding the option to render all files found in directory with the files that are not part of the project grayed slightly out? You could even add an option to "include in proejct". Radical I know.</li></ol><div><br /></div><div>This concludes my rant, I hope that despite being harsh at times, it shines through how very much I love Qt. I think there is truth in the Norwegian saying "man tukter den man elsker" literally "You hurt those you love". I yearn for it to be event better!</div><div><br /></div>OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-91574751938549260942022-01-12T03:58:00.004+01:002022-01-12T03:58:27.200+01:00One year without a single update can't be good right? Happy new year 2022!<p> </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhKLwO8KLOXyxDgw4HY9D7pcV2XRyvAdHYSqQHncxXSVnBVbei0YjoL5voxmblp0XwOSdR2L7jOFJ9xyOei7ZzF_73Rg0JAozwy9bbHIi3cXotH532EFhJD0HKzSAphm5U68lAyO8KTjKzTZltmdaP-skr5o0L93Xu5tDiCbAKSwL7hG0ztfePfh6YjQw=s1900" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1828" data-original-width="1900" height="616" src="https://blogger.googleusercontent.com/img/a/AVvXsEhKLwO8KLOXyxDgw4HY9D7pcV2XRyvAdHYSqQHncxXSVnBVbei0YjoL5voxmblp0XwOSdR2L7jOFJ9xyOei7ZzF_73Rg0JAozwy9bbHIi3cXotH532EFhJD0HKzSAphm5U68lAyO8KTjKzTZltmdaP-skr5o0L93Xu5tDiCbAKSwL7hG0ztfePfh6YjQw=w640-h616" width="640" /></a></div><br /><p></p><p>OctoMY has pretty much been in hibernation through 2021, even more so than in <a href="http://blog.octomy.org/2020/12/funding-of-octomy-and-general-status.html">2021</a>. Please rest assured that we are still on track with the <a href="http://blog.octomy.org/2020/01/happy-anniversary-2020.html">original plan</a> of securing funding for the project going forward.</p><p>I still can't disclose what exactly that means, and for now it is enough to say that really it is not important. The important however thing is that the project will be revamped and brought to the front again hopefully starting this year!</p><p>2 Years is eons in tech, and as expected a lot has happened. Qt6 has been released. Robots are everywhere and the need for OctoMY is growing by the minute!</p><p>Stay tuned!</p>OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-30818965921621706812020-12-31T19:33:00.007+01:002020-12-31T20:01:57.253+01:00Funding of OctoMY™ and general status<p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9WESlii76BCy4uJq-84WnSUKUKssctfcZ9VrDVnrFRJJVXXQteyo2NR0mivTe9UQHJfVyUAhZzyDo3AUrN0z_FpOYMhBsTAPFzzvKWKEzQHBKdUs7Fwa2-cT-wP-pys1EYuj3OQcnOcZb/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="380" data-original-width="626" height="388" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9WESlii76BCy4uJq-84WnSUKUKssctfcZ9VrDVnrFRJJVXXQteyo2NR0mivTe9UQHJfVyUAhZzyDo3AUrN0z_FpOYMhBsTAPFzzvKWKEzQHBKdUs7Fwa2-cT-wP-pys1EYuj3OQcnOcZb/w640-h388/image.png" width="640" /></a></div><br /><br /><p></p><p>Progress on OctoMY™ has <a href="http://blog.octomy.org/2020/01/happy-anniversary-2020.html">as promised</a> slowed down in year 2020. A lot has happened behind the scenes. and in this post I hope to better explain what has been going on.</p><p>In one sentence: I put development of OctoMY™ on hold temporarily while working on a project that can <u>fund the future development of OctoMY™</u>.</p><p>Why did I do this? I realized that organically growing the OctoMY™ project as an open source project as I first planned was not feasible from it's current state. I would have to devote all my time selling the concept to unsuspecting developers rather than advancing the development status and even then I would risk attracting very few and/or very junior resources to the project.</p><p>So I decided to switch gears and start another secret unrelated project that could generate some revenue. I will not disclose any details about this project because it is truely not relevant (and I do not wish to attract any attention to this project as it is a strictly commercial B2B project).</p><p>However after exactly one year of focusing 100% of my development time into this new project (Let's call this project "FK") I feel at least I owe blog readers a status update!</p><p>The status is that I have gone through <a href="https://en.wikipedia.org/wiki/Development_hell">development hell</a> on FK, and I am finally emerging victorious on the other end. I created an MVP over 6 months ago and was ready to launch, but decided to create a second MVP (<a href="https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/">biggest nono in history of IT</a>) that had major feature creep. We live and we learn. The important positive takeaways here are:</p><p></p><ul style="text-align: left;"><li>The FK project is 95% ready to launch.</li><li>The FK that will release now is much better than the original MVP, making it much more likely to succeed.</li><li>The FK codebase is reusable, modular and useful beyond the hot mess it was at the start. In fact many of the useful parts have now been made open source and <a href="https://gitlab.com/octomy">rebranded as octomy projects in gitlab</a>.</li><li>I learned a lot of new technologies during my one year of FK development; <a href="http://blog.octomy.org/2020/02/docker-registry-credentials-as.html">Kubernetes & Docker</a>, <a href="http://blog.octomy.org/2020/11/deploying-python-pacakges-to-pypi-using.html">Python</a>, FastAPI, flask, ... The list goes on and on... </li><li>I also had the oportunity to form some opinions on good practices along the way, which I would have had to do anyway for the OctoMY™ server side. I just practiced it on the FK project instead of having to do it for OctoMY™ directly.</li><li>And maybe most importantly: When the FK project launches I hope to see a solid revenue stream that eventually will trickle into OctoMY™ in the form of my spare time (I will be able to start working on FK and OctoMY™ full time instead of just my spare time.</li></ul><div>I hope this status update is sufficient to explain why it appears that development stopped completely. If you look in the <a href="https://gitlab.com/octomy">octomy group in gitlab</a> you will see that is far from the case. 7 (!!) new projects were added 2 weeks ago.</div><div><br /></div><div><br /></div><div>And with that I wish you all a happy 2021!</div><div><br /></div><div><br /></div><div><br /></div><p></p>OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-88279462528465595362020-11-26T00:25:00.006+01:002020-12-31T20:11:08.590+01:00 Deploying python pacakges to PyPi using gitlab and twine<p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipBA8V0XBUHPliOA6IgqQZLOqp01NQeJA2G49xlMuGDU8n0UFdIeWrtWR0iY5hfpjJkDpgg8qRQP8GO3PbeMAwATmSv1fTTJaoJ-bwaQ7Y-BFy1RXqFPmDDx-SsI3M8yYMGhGJ1-ZyIfZD/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="797" data-original-width="564" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipBA8V0XBUHPliOA6IgqQZLOqp01NQeJA2G49xlMuGDU8n0UFdIeWrtWR0iY5hfpjJkDpgg8qRQP8GO3PbeMAwATmSv1fTTJaoJ-bwaQ7Y-BFy1RXqFPmDDx-SsI3M8yYMGhGJ1-ZyIfZD/w453-h640/image.png" width="453" /></a></div><br /><br /><p></p><p>While working on the <a href="https://gitlab.com/octomy/web-minify">web-minify project</a>, I had to figure out just how it is possible to deploy a Python package to PyPi from gitlab. Here are my findings, hopefully it is useful for someone else!</p><h3 style="text-align: left;">Key information<br /></h3><ul style="text-align: left;"><li>The <a href="https://docs.gitlab.com/runner/executors/docker.html">gitlab docker executor</a> will run each job in a separate container.</li><li>No data is shared between jobs by default, so <b>you have to use build artifacts to facilitate sharing between jobs</b><br /></li><li>The build job can thus prepare the package data in the <i>dist/</i> folder ready for deployment and then mark the <i>dist/</i> folder as a build artifact<br /></li><li>The deploy job will then have the <i>dist/</i> folder available (all subsequent jobs after a build artifact has been defined will have access to the artifacts)</li><li>The deploy job can then invoke twine to upload the package to PyPi</li><li>Twine takes a username and a password from a configuration file<br /></li><li> To avoid storing the password in the source code, a TWINE_PASSWORD environment variable is set in <a href="https://docs.gitlab.com/ee/ci/variables/">gitlab configuration</a> of the project.</li><li>PyPi supports <a href="http://pyfound.blogspot.com/2019/07/pypi-now-supports-uploading-via-api.html">uploading packages using API tokens</a> instead of requiring a username/password. In this mode the username is set to "__token__" and the password is actually a long token that you get from twine config upon creation of the token instead of an actual personal password. This allows us to have some granularity of permissions, creating a token that can only access one project instead of all the projects of a user. Anyway, the token is set as a <a href="https://docs.gitlab.com/12.10/ee/ci/variables/">gitlab variable</a> called TWINE_PASSWORD.</li></ul><p>You can look at the <a href="https://gitlab.com/octomy/web-minify/-/blob/master/.gitlab/ci.yaml">.gitlab-ci.yaml</a> and <a href="https://gitlab.com/octomy/web-minify/-/blob/master/Makefile">Makefile</a> of the the <a href="https://gitlab.com/octomy/web-minify">web-minify project</a> to see an example of how this is done.</p><p><br /></p><p>Good luck!</p><p><br /></p><p><br /></p>OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-57427608272879689062020-02-02T00:09:00.005+01:002020-12-31T20:07:08.335+01:00Docker registry credentials as secretGenerator with kustomize<div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFYV5SDL7mB88DKNZLTwnv6CVYQMJUngiiJdxtFI6IEre4pz7sqe3au5JfvCmbc4OqL-CiEbEaGPFYS44NP8vwSqr3uTeXmrW1LuU_HBIW0QsLOdO0l__dC66qi8QyUgAKm6e2HTjRfbGX/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1143" data-original-width="736" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFYV5SDL7mB88DKNZLTwnv6CVYQMJUngiiJdxtFI6IEre4pz7sqe3au5JfvCmbc4OqL-CiEbEaGPFYS44NP8vwSqr3uTeXmrW1LuU_HBIW0QsLOdO0l__dC66qi8QyUgAKm6e2HTjRfbGX/w413-h640/image.png" width="413" /></a></div><br /><br /></div>So you just discovered your new friend kustomize, and now you want to convert all your pesky secrets into secretGenerators. Good for you!<br />
<br />
<br />
But... what about the docker registry credentials secret? It seems like magic that just works. Fear not, here is the definitive guide to how you can convert it to secretGenerator!<br />
<br />
<br />
So let's assume you start with the following working setup:<br />
<br />
<br />
Inside secret-docker-reg.yaml we have the following YAML:<br />
<br />
<pre class="c-mrkdwn__pre" data-darkreader-inline-color="" data-stringify-type="pre" style="--darkreader-inline-color: #d6d2cd; --saf-0: rgba(var(--sk_foreground_low,29,28,29),0.13); -webkit-text-stroke-width: 0px; background: rgba(var(--sk_foreground_min,29,28,29),0.04); border-radius: 4px; border: 1px solid var(--saf-0); box-sizing: inherit; color: #1d1c1d; counter-reset: list-0 0 list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; font-family: Monaco, Menlo, Consolas, "Courier New", monospace; font-size: 12px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: none; font-weight: 400; letter-spacing: normal; line-height: 1.50001; margin: 4px 0px; orphans: 2; overflow-wrap: break-word; padding: 8px; tab-size: 4; text-align: left; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-break: normal; word-spacing: 0px;">apiVersion: v1
files:
- secret-docker-reg.json
kind: Secret
metadata:
name: docker-reg
namespace: whatever
type: kubernetes.io/dockerconfigjson
<a class="c-link" data-darkreader-inline-color="" href="https://slack-redir.net/link?url=http%3A%2F%2Fkubernetes.io%2Fdockerconfigjson" rel="noopener noreferrer" style="--darkreader-inline-color: inherit; box-sizing: inherit; color: inherit; text-decoration: none;" target="_blank"></a></pre>
<br />
Inside secret-docker-reg.json we have the following JSON:<br />
<br />
<pre class="c-mrkdwn__pre" data-darkreader-inline-color="" data-stringify-type="pre" style="--darkreader-inline-color: #d6d2cd; --saf-0: rgba(var(--sk_foreground_low,29,28,29),0.13); -webkit-text-stroke-width: 0px; background: rgba(var(--sk_foreground_min,29,28,29),0.04); border-radius: 4px; border: 1px solid var(--saf-0); box-sizing: inherit; color: #1d1c1d; counter-reset: list-0 0 list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; font-family: Monaco, Menlo, Consolas, "Courier New", monospace; font-size: 12px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: none; font-weight: 400; letter-spacing: normal; line-height: 1.50001; margin: 4px 0px; orphans: 2; overflow-wrap: break-word; padding: 8px; tab-size: 4; text-align: left; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-break: normal; word-spacing: 0px;">{"auths":{"<a class="c-link" data-darkreader-inline-color="" href="https://slack-redir.net/link?url=https%3A%2F%2Fregistry.gitlab.com" rel="noopener noreferrer" style="--darkreader-inline-color: inherit; box-sizing: inherit; color: inherit; text-decoration: none;" target="_blank">https://registry.gitlab.com</a>":{"username":"yourusername","password":"SOME SECRET PASSWORD STRING","auth":"SOME SECRET AUTH STRING"}}}</pre>
<br />
Alternatively your secret-docker-reg.yaml may look like this:<br />
<pre class="c-mrkdwn__pre" data-darkreader-inline-color="" data-stringify-type="pre" style="--darkreader-inline-color: #d6d2cd; --saf-0: rgba(var(--sk_foreground_low,29,28,29),0.13); -webkit-text-stroke-width: 0px; background: rgba(var(--sk_foreground_min,29,28,29),0.04); border-radius: 4px; border: 1px solid var(--saf-0); box-sizing: inherit; color: #1d1c1d; counter-reset: list-0 0 list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; font-family: Monaco, Menlo, Consolas, "Courier New", monospace; font-size: 12px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: none; font-weight: 400; letter-spacing: normal; line-height: 1.50001; margin: 4px 0px; orphans: 2; overflow-wrap: break-word; padding: 8px; tab-size: 4; text-align: left; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-break: normal; word-spacing: 0px;">apiVersion: v1
data:
- inlined-json: eyJhdXRocyI6eyJodHRwczovL3JlZ2lzdHJ5LmdpdGxhYi5jb20iOnsidXNlcm5hbWUiOiJ5b3VydXNlcm5hbWUiLCJwYXNzd29yZCI6IlNPTUUgU0VDUkVUIFBBU1NXT1JEIFNUUklORyIsImF1dGgiOiJTT01FIFNFQ1JFVCBBVVRIIFNUUklORyJ9fX0=
kind: Secret
metadata:
name: docker-reg
namespace: whatever
type: kubernetes.io/dockerconfigjson</pre>
<br />
As you can see the difference is that in the first example the credentials is in a separate .json file referenced by the YAML (secret-docker-reg.json) while in the second the json content has been base64 encoded diretly into the YAML file.<br />
<br />
Now to convert this to a kustomize secretGenerator you will need to keep the json in a separate file. In the first example you are already good to go, in the second simply copy the rather long base64 string (eyJhdXRocyI6eyJodHRwczovL3JlZ2lzdHJ5LmdpdGxhYi5jb20iOnsidXNlcm5hbWUiOiJ5b3VydXNlcm5hbWUiLCJwYXNzd29yZCI6IlNPTUUgU0VDUkVUIFBBU1NXT1JEIFNUUklORyIsImF1dGgiOiJTT01FIFNFQ1JFVCBBVVRIIFNUUklORyJ9fX0=) into a separate file such as temp.txt and run the following command:<br />
<pre class="c-mrkdwn__pre" data-darkreader-inline-color="" data-stringify-type="pre" style="--darkreader-inline-color: #d6d2cd; --saf-0: rgba(var(--sk_foreground_low,29,28,29),0.13); -webkit-text-stroke-width: 0px; background: rgba(var(--sk_foreground_min,29,28,29),0.04); border-radius: 4px; border: 1px solid var(--saf-0); box-sizing: inherit; color: #1d1c1d; counter-reset: list-0 0 list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; font-family: Monaco, Menlo, Consolas, "Courier New", monospace; font-size: 12px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: none; font-weight: 400; letter-spacing: normal; line-height: 1.50001; margin: 4px 0px; orphans: 2; overflow-wrap: break-word; padding: 8px; tab-size: 4; text-align: left; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-break: normal; word-spacing: 0px;">cat temp.txt | base64 -d > secret-docker-reg.json</pre>
<br />
This will decode the base64 into the json format in the file we want. NOTE: You could also use an online base64 conversion tool, but since this string contains credentials to your docker registry, you may want to use one you really trust and only over https.<br />
<br />
What remains is to create the kustomize secretGenerator stanza:<br />
<br />
<pre class="c-mrkdwn__pre" data-darkreader-inline-color="" data-stringify-type="pre" style="--darkreader-inline-color: #d6d2cd; --saf-0: rgba(var(--sk_foreground_low,29,28,29),0.13); -webkit-text-stroke-width: 0px; background: rgba(var(--sk_foreground_min,29,28,29),0.04); border-radius: 4px; border: 1px solid var(--saf-0); box-sizing: inherit; color: #1d1c1d; counter-reset: list-0 0 list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; font-family: Monaco, Menlo, Consolas, "Courier New", monospace; font-size: 12px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: none; font-weight: 400; letter-spacing: normal; line-height: 1.50001; margin: 4px 0px; orphans: 2; overflow-wrap: break-word; padding: 8px; tab-size: 4; text-align: left; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-break: normal; word-spacing: 0px;">secretGenerator:
- name: docker-reg
files:
- secret-docker-reg.json
type: <a class="c-link" data-darkreader-inline-color="" href="https://slack-redir.net/link?url=http%3A%2F%2Fkubernetes.io%2Fdockerconfigjson" rel="noopener noreferrer" style="--darkreader-inline-color: inherit; box-sizing: inherit; color: inherit; text-decoration: none;" target="_blank">kubernetes.io/dockerconfigjson</a></pre>
<br />
Things to watch out for:<br />
<br />
<ul>
<li>The secretGenerator stanza must be inside a kustomization.yaml file as it is part of kustomize and NOT part of kubernetes/kubectl.</li>
<li>The .json file needs to be on the same level or below the kustomize.yaml file from which it is referenced. If not you will get nasty errors about this.</li>
</ul>
And that's it! I hope this saved your ass like it would have saved mine if I had found it before I knew. Oh wait... OctoMY™http://www.blogger.com/profile/11057445196202408351noreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-26588876674202276362020-01-06T18:41:00.001+01:002020-12-31T19:52:04.972+01:00Happy Anniversary 2020!<div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxzPaLY7Nh6_TIH-62_p43G7EQgtScRDJ7StwwgegTWjOeaP6fOG8EZiRbWxxtNYjs4r17QtT4xbE3z_fwscLsKs3-7t-UYQFJYcmTB5Kw06mNnUh688NTjyRGmV2evoTGLbIqlXdtybgX/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="375" data-original-width="500" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxzPaLY7Nh6_TIH-62_p43G7EQgtScRDJ7StwwgegTWjOeaP6fOG8EZiRbWxxtNYjs4r17QtT4xbE3z_fwscLsKs3-7t-UYQFJYcmTB5Kw06mNnUh688NTjyRGmV2evoTGLbIqlXdtybgX/w640-h480/image.png" width="640" /></a></div><br /><br /></div>The 7th of January 2020 marks the four year anniversary of the OctoMY™ project. The project has had some amazing progress as always, and just a few months ago a new strategy was formed that may slow development down momentarily.<br />
<br />
More on that later.<br />
<br />
Suffice to say, I am happy as ever to work on this project, and I am looking forward to an amazing 2020.<br />
<br />
<br />Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-6291734140204335614.post-23764184419004342792019-12-21T23:16:00.000+01:002019-12-21T23:16:01.058+01:00Productivity matrixI have been thinking about productivity lately. I have dubbed my idea "swat matrix team", deriving from the fact that it talks about how to organize teams in a way that both resembles "swat" teams and leverages the skills of individual team members as a "matrix. (Sorry Neo, you are not the inspiration this time).<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhP1OxmGyezZE0ujGCtY1RlxQ2fLYZRUSDGx5hh8PRPb7Ifax1WuhknzoU24J07UJ3jJIKzKRmgjImLticH5j8rfdw-RH228TfCgoQSxXnCFccJdBfp11Ohg5olfNsh9HdZakVxfnnGdsM/s1600/morgan-allen-swat-robot-resized.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="685" data-original-width="1600" height="273" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhP1OxmGyezZE0ujGCtY1RlxQ2fLYZRUSDGx5hh8PRPb7Ifax1WuhknzoU24J07UJ3jJIKzKRmgjImLticH5j8rfdw-RH228TfCgoQSxXnCFccJdBfp11Ohg5olfNsh9HdZakVxfnnGdsM/s640/morgan-allen-swat-robot-resized.jpg" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Swat robots. Image credit <a href="https://genr8ion.artstation.com/" target="_blank">Morgan Allen</a>.</td></tr>
</tbody></table>
The gist of it is that we create a small team of resources each expert in their own domains working together like a unit ("swat" team). For example you have one dev-ops, one UX, one back-end and one front-end specialist working on the same project.<br />
<br />
All should take part in git review for each other and try to learn the trades of each other. In fact the learning should be formalized in rotating bi-weekly "apprenticeships designations" where pairs of team members are responsible for mentoring each other in their respective fields of expertise. For example dev-ops will teach deployment in kubernetes to UX, UX will teach user testing to dev-ops.<br />
<br />
The actual work for the project will be the learning material used. In this example UX Tasks will be assigned 25% to the UX apprentice with the tasks with most learning potential being assigned first.<br />
<br />
The idea is that by doing things you are not comfortable with you will be on high alert and your attention to detail and best practices will be heightened. By having an expert by your side you can maintain confidence that the result will pass the bar.<br />
<br />
For larger projects multiple swat teams will work together. The apprenticeship is maintained within each team, and each team is responsible for one easily separable part of the project. Rotation of the members will happen between teams, so that the UX of one team will swap with the UX of another, facilitating cross-team knowledge sharing while still maintaining coherent teams.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-74705111008773516502019-12-20T02:54:00.001+01:002019-12-20T02:54:47.128+01:00Screens vs productivityIt's been awfully quiet lately in the OctoMY™camp. Things are moving under the hood as always, albeit in a different manner than you might think.<br />
<br />
All development has been put on hold the last few months an a new secret project has been put into motion in an effort to gather some funds for OctoMY™.<br />
<br />
Without spoiling anything, here is a tip that might help you improve productivity in your own projects!<br />
<br />
Buy more screens. Lots of them. My current setup is like this:<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQcXuzTW7pjQZjjaRGRLjyL1HW8ph-Wxo8rD0w-O2sWWdatcxkMtvXKOipBNdo5vz3bs0WwCIfWedNpIo_VpKl1axQXc8MH_XR32ryESxEnLua6xc2070FKg5LL0QyubQwRtvYiADOmTY/s1600/IMG_20191220_024127.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1200" data-original-width="1600" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQcXuzTW7pjQZjjaRGRLjyL1HW8ph-Wxo8rD0w-O2sWWdatcxkMtvXKOipBNdo5vz3bs0WwCIfWedNpIo_VpKl1axQXc8MH_XR32ryESxEnLua6xc2070FKg5LL0QyubQwRtvYiADOmTY/s640/IMG_20191220_024127.jpg" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Big-H configuration</td></tr>
</tbody></table>
I have two vertically aligned 1080P 24" screens on the sides and two 4k 28" horizontal screens in the middle. The three "tiny" 15" screens above are actually touch screen computers. I use them for testing OctoMY builds during development and for showing operations statistics.<br />
<br />
Anyways, getting used to this amount of screen real estate takes some time, but after you get used to it there is no going back. Your brain will accept and learn to take advantage of windows staying put in one location without having to switch around too much, and your way of working and speed will gradually increase.<br />
<br />
<br />
Also a bonus tip that has also contributed to my current level of working speed; leave your computer and screens on even when you are not using it. I know this is a big no-no in todays environment-focused mindset. I think of it this way; the innovation I create with this setup will in the future far offset the power I spent having my screens on. And if you don't feel the same, convert your energy supply to a environmentally friendly one. You should have done that regardless if you really care....<br />
<br />
Have fun and happy coding!<br />
<br />Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-6291734140204335614.post-49395151376183393702019-08-06T09:32:00.002+02:002019-08-06T09:37:38.211+02:00Area 51 Raid T-ShirtsJust a quick word of our first ever sponsor!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://firstkissdesigns.com/collections/area-51" target="_blank"><img border="0" data-original-height="1080" data-original-width="1081" height="319" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqslTLJWJVE6DmvbkZfyZNpAfyXg5Mab8wVd7Kue4jYU2YxFKlSewFe7KPWpIxZ8XmmNPcgUDMfePmnAegyFOtNCV-Ha-okeWrFnW0toaapQryMnpgkgDSOYpMSfm5r1mttFWK3ggMcNE/s320/fb_in_rememberance_of_the_great_raid_area51.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<a href="https://firstkissdesigns.com/collections/area-51" target="_blank">Get your Area 51 T-Shirts here</a>.
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-88381231445383482012019-07-04T03:36:00.001+02:002019-07-05T19:15:47.997+02:00Plan is dead, long live Dogma!As explained in the <a href="http://blog.octomy.org/2019/06/strategy-update.html">strategy update of 2019-06-16</a>, We will <a href="https://sites.google.com/a/octomy.org/octomy/documentation/development/architectual-overview/dogma">continue the effort of completing the "plan"</a> part of OctoMY™. But "plan" is not the best of word to describe this concept. In this post will explore the alternatives. I want the word we settle on to be self explanatory, short and memorable.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgV6Vzo_2B30zpuZZ7o9U7DmNFmFF2GMp4-NHGSMOhyt8uJKxAcBH883yehqGMjJ8R8TIjSbnoJP8YXNw5b5pb2E2_mnrU3PGWghz3jADr8qisW1-4V139Z8vwY1BhL9ApF8GWXlPvkRE/s1600/danger_robots_at_work.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="723" data-original-width="1000" height="231" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgV6Vzo_2B30zpuZZ7o9U7DmNFmFF2GMp4-NHGSMOhyt8uJKxAcBH883yehqGMjJ8R8TIjSbnoJP8YXNw5b5pb2E2_mnrU3PGWghz3jADr8qisW1-4V139Z8vwY1BhL9ApF8GWXlPvkRE/s320/danger_robots_at_work.png" width="320" /></a></div>
<br />
<br />
So what is it that we will be naming?<br />
<br />
It is a declaration of all the rules by which a group of agents will abide. The rules are written in a declarative language where the possible states and the possible transitions between them are described in high level terms.<br />
<br />
The transitions are triggered by external events available to the individual agent via their respective hardware, and deterministic logic, and it is up to the individual agent to determine in which state they ought to be at any point in time.<br />
<br />
The collaboration of agents is supported by the specification of shared secrets that allow agents to communicate securely whenever within range of one another. Each agent may interpret communication received from both trusted and distrusted agents.<br />
<br />
Agents are expected to have a set of sensors that provide good input to form events from. Events may be such things as a change in location, a discovery of a landmark or identification of a person.<br />
<br />
While the "rules" are usually handwritten by the people that own the agents, it should be possible to generate the rules programatically, and the syntax of the language may be extended in the future to support powerful open-ended ways of controlling the agents.<br />
<br />
Using <a href="https://www.thesaurus.com/">https://www.thesaurus.com</a> I have arrived at the following alternatives that more succinctly describe what may be the most important part of the OctoMY™ project:<br />
<ul>
<li><a href="https://www.dictionary.com/browse/decree">Decree</a></li>
<li><a href="https://www.dictionary.com/browse/precept">Precept</a></li>
<li><a href="https://www.dictionary.com/browse/prescript">Prescript</a></li>
<li><a href="https://www.dictionary.com/browse/dogma">Dogma</a></li>
<li><a href="https://www.dictionary.com/browse/doctrine">Doctrine</a></li>
<li><a href="https://www.dictionary.com/browse/edict">Edict</a></li>
<li><a href="https://www.dictionary.com/browse/ordinance">Ordinance</a></li>
<li><a href="https://www.dictionary.com/browse/tenet">Tenet</a></li>
</ul>
<div>
From this, I think the one I like the most is "Dogma". While edict is maybe more accurate, dogma sounds cooler and I never heard the word edict before I did this research. So from now on, "plan" will be renamed to "Dogma".</div>
<div>
<br /></div>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-6291734140204335614.post-68622278837350277472019-06-16T03:01:00.001+02:002019-06-16T03:01:28.553+02:00Migration from github to gitlab completeAfter the <a href="http://blog.octomy.org/2018/06/octoym-will-transition-from-github-to.html">last post on migration away from github</a>, I have finally been able to act on it!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioFo9TnBGl9_QS-AoPDKSKEhyphenhyphenRrV9BM1R6NhV8gxoFnRikmeY2kmOGWjJl_L0jXbh2lPE1ImP6_9xJSzdfCbktEGMWT8l-EsnXRZv31quycTQiX-XIBdPJDYeaz5ppWnwevvpNfu5ooE8/s1600/gitlab-github-comparison.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="400" data-original-width="700" height="365" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioFo9TnBGl9_QS-AoPDKSKEhyphenhyphenRrV9BM1R6NhV8gxoFnRikmeY2kmOGWjJl_L0jXbh2lPE1ImP6_9xJSzdfCbktEGMWT8l-EsnXRZv31quycTQiX-XIBdPJDYeaz5ppWnwevvpNfu5ooE8/s640/gitlab-github-comparison.png" width="640" /></a></div>
<br />
<br />
From today the official git repository provider of OctoMY™ will be <b>gitlab</b> under the following url:<br />
<br />
<a href="https://gitlab.com/octomy/octomy">https://gitlab.com/octomy/octomy</a><br />
<br />
A mirror has been set up so that all pushes to gitlab will automatically be available on <b>github</b>. This will maintain any SEO and existing users or users preferring github. Also <b>Travis CI</b> only supports github. For the future we are looking into using some of <a href="https://about.gitlab.com/product/continuous-integration/">gitlab's built in CI functionality</a> as well.<br />
<br />Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-6291734140204335614.post-37034581573001852312019-06-16T01:22:00.001+02:002019-06-16T01:22:17.525+02:00Strategy UpdateSince the beginning of this year untill now I have had exceptional progress on the OctoMY™ project, in large part thanks to the <a href="https://www.blogger.com/2019/01/happy-anniversary-2019.html">few bold goals set in the beginning of the year</a>.<br />
<br />
I have managed to <a href="https://www.blogger.com/2019/02/february-update.html">deliver</a> on this plan, and I consider this strategy change was a success. By maintaining motivation for development and also digging the project out of some really bad places, it is now in a much better shape. So where is the MVP?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6rc38ZbFiDs8qL-8v_MiHEYWHN_bmySEQN3KWlNqRrAA0DMOTWJ8eOBnFNY9WMvs2utzMLT5dkOBjYpcKLqsjaV9vRcEyRnREFaInXt3S8XdMcTWrd92ASl2p9RkZ1Fvz5nWC4sRp5Po/s1600/change-of-strategy.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="620" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6rc38ZbFiDs8qL-8v_MiHEYWHN_bmySEQN3KWlNqRrAA0DMOTWJ8eOBnFNY9WMvs2utzMLT5dkOBjYpcKLqsjaV9vRcEyRnREFaInXt3S8XdMcTWrd92ASl2p9RkZ1Fvz5nWC4sRp5Po/s400/change-of-strategy.jpg" width="400" /></a></div>
<br />
<br />
During the process many bad things have come to light both from architecture but also from a code perspective, which is good. And most of them have been mitigated somehow, either by refactoring, removing or rewriting, which is awesome! But <i>one big issue remains</i> which has proven hard to fix; the asynchronous stores.<br />
<br />
At some point in the distant past I decided that I needed a generic component that would allow me to access data asynchronously. The problem that prompted this was keystore. Generating a key takes several seconds, and large parts of the application are useless unless there is a key present. However, having the UI pause for several seconds at start up was rightfully deemed unacceptable, so I created a way to generate the key in a background thread and wrapped all access to the key in a layer of futures with stored list of callbacks. So if you wanted the key, instead of doing<br />
<br />
<br />
myKey=keystore.getKey();<br />
<br />
you would do the following:<br />
<br />
keystore.getKey().onFinished([](myKey){ /*do whatever with the key*/})<br />
<br />
<br />
While this system seemed simple enough, it soon became clear that the implementation would be non-trivial. How could I ensure that the callback was executed from the same thread that booked it?<br />
<br />
In Qt this is very important. Also I decided that I should use this fancy new asyncronous API for other parts of the program, not just keystore. Before I knew it it had bloated up and become difficult to manage. The API had diverged into several simplification layers on top and it was getting really messy.<br />
<br />
Also, one of the main ideas of OctoMY™ was the concept of a "plan", which basically is a small language that would describe a configuration of many nodes completely, and allow them to collaborate on pretty elaborate tasks from the rules of their common "plan". While some effort was made to allow for easily editing and parsing plan files, it never really took the center stage of storing data about nodes. Currently data is spread out among the following stores:
<br />
<br />
<ul>
<li><b>keystore</b> - keypair for local and pubkeys for friends</li>
<li><b>addressbook</b> - friends data such as name gender and type (except key, which is in keystore)</li>
<li><b>localidentity</b> - local data such as name gender and type (except key, which is in keystore)</li>
<li><b>agentconfig</b> - agent spesific configuration such as controller card config and similar</li>
<li><b>settings</b> - all non-essential settings such as window placements and last selected items.</li>
</ul>
Many of these "stores" are customers of the aforementioned asynchronous API and all of them show bugs, preventing us from getting to an MVP.<br />
<br />
So now it's time for a new update to the strategy, to attack this last problem standing in the way of our glorious MVP! This time around we will focus on the following:<br />
<ul>
<li><b>plan spec</b> - Spec up a decent first version of the plan. Take whatever we learned form the asynchronous store into consideration and ensure the spec is clean and nice.</li>
<li><b>plan implementation</b> - Implement the plan spec to have a first working version.</li>
<li><b>plan test</b> - Implement a full test suite for the plan implementation to gain full confidence in it.</li>
<li><b>plan integration</b> - Integrate the plan by replacing each store one by one.</li>
</ul>
Once this plan business is out of the way then:<br />
<br />
<ul>
<li><b>MVP</b> - Continue work towards MVP.</li>
</ul>
While this approach in many ways constitutes "one step back, two steps forward", I think it is the better way. By doing this we address the real problems in front of us in a good way and can move forward with our pride intact. The alternative is soldiering on with debugging the asynchronous API, but I think that is not a fruitful use of time at this point.<br />
<br />
Work on the plan spec has already begun, and I will try to keep this blog with some updates along the way. Stay tuned!<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-44594882042189510552019-06-15T00:49:00.003+02:002019-06-15T00:49:31.064+02:00DJI Robomaster S1Definitely on my wishlist!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" frameborder="0" height="360" src="https://www.youtube.com/embed/8lquX-imy6o?feature=player_embedded" width="680"></iframe></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6291734140204335614.post-83013547005034218392019-05-19T01:25:00.001+02:002019-05-19T01:25:35.917+02:00Short progress reportDespite hectic personal life with a dash of illness on top I have manged to make progress on OctoMY!<br />
<br />
Here is a screenshot of my latest creation; the debugger widget. Basically I decided to make all internals of the node explicitly available through a debugging user interface. The feedback and interaction this provides greatly expands on what has been available through the log output that has served as the primary debugging data so far:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4Oml2OoQj9rgyjrMaXcPuJ6eR2uCod7-WPhF0L6W8levhxLIhXxEVhuTQXcwTpaHH3NlSn5T6-1vSeFDzxQDAQzp_Rrj5W1UZmcLDNSiFvGDgYuLNSDGh0SgpzWgRE10Kp0QWERgiQVs/s1600/OctoMY%25E2%2584%25A2+Debugger_021.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4Oml2OoQj9rgyjrMaXcPuJ6eR2uCod7-WPhF0L6W8levhxLIhXxEVhuTQXcwTpaHH3NlSn5T6-1vSeFDzxQDAQzp_Rrj5W1UZmcLDNSiFvGDgYuLNSDGh0SgpzWgRE10Kp0QWERgiQVs/s1600/OctoMY%25E2%2584%25A2+Debugger_021.png" width="100%" /></a></div>
Unknownnoreply@blogger.com0