devel.grys.ithttps://devel.grys.it/2022-11-04T00:59:32+01:00Nextcloud take 22022-11-04T00:30:00+01:002022-11-04T00:59:32+01:00Gianlucatag:devel.grys.it,2022-11-04:/nextcloud-take-2.html<p>After some months (and tanks to some random people on Internet), I decided to give Nextcloud another chance... Well, not really.</p>
<p>Back in February, I got sick of the problems I had upgrading Nextcloud which nearly destroyed my server. A server that as also some
public sites I am running …</p><p>After some months (and tanks to some random people on Internet), I decided to give Nextcloud another chance... Well, not really.</p>
<p>Back in February, I got sick of the problems I had upgrading Nextcloud which nearly destroyed my server. A server that as also some
public sites I am running.</p>
<p>After dropping Nextcloud, I still had the problem of synchronize the files on 3 PC (2 Linux and 1 windows) and a phone, so I tried out Syncthing. It was a good enough solution but I found it miss something, expecially in the configuration aspect. Maybe I set up it wrong, but I had to duplicate a bunch of locations to make it work.</p>
<p>Anyway, talking to someone, I got the suggestion to use Nextcloud in a Docker container that should make it easy to integrate in a system with other complex software. Fine, let's try it.</p>
<p>Good point: the installation were smooth enough. Even with the basic image and commands, Nextcloud was up and running in no time. <br>
Bad point: the default image is bugged. It work well with a browser, but if you want a desktop client, it does not work.</p>
<p><strong>The error</strong>
The error you get, aside a warning in the web browser, while trying to login with a Desktop client (or mobile app) is:</p>
<p><em>The polling URL does not start with HTTPS despite the login URL started with HTTPS. Login will not be possible because this might be a security issue. Please contact your administrator.</em></p>
<p>which is what ?</p>
<p>After some digging, I found out that the cause is a missing option in the <em>config.php</em> file, more precisely (at lease in my case)</p>
<p><code>'overwriteprotocol' => 'https',</code> </p>
<p>Ok, simple enough to fix... or that is what I was thinking... I was wrong by a long shot.</p>
<p><strong>The problem</strong>
Simple, my Nextcloud was running inside a docker container and I am no expert in Docker. So, while I know it is possible, I have no idea how to change the docker-compose rules to either</p>
<ul>
<li>allow to extract a file to the host machine</li>
<li>include the option in the build process</li>
</ul>
<p><strong>The solution</strong>
After some failed attempts, I solved this in the least optimal solution but hey, it worked.</p>
<p>This is the set of commands I used. With </p>
<div class="highlight"><pre><span></span><code>docker ps -a
</code></pre></div>
<p>I got the id of the container, then with </p>
<div class="highlight"><pre><span></span><code><span class="nv">docker</span><span class="w"> </span><span class="k">exec</span><span class="w"> </span><span class="mi">9</span><span class="nv">cf084d19db4</span><span class="w"> </span><span class="nv">sh</span><span class="w"> </span><span class="o">-</span><span class="nv">c</span><span class="w"> </span><span class="s2">"head -46 config/config.php > config/test.php"</span><span class="w"></span>
<span class="nv">docker</span><span class="w"> </span><span class="k">exec</span><span class="w"> </span><span class="mi">9</span><span class="nv">cf084d19db4</span><span class="w"> </span><span class="nv">sh</span><span class="w"> </span><span class="o">-</span><span class="nv">c</span><span class="w"> </span><span class="s2">"echo \'overwriteprotocol\' =\> \'https\', >> config/test.php"</span><span class="w"></span>
<span class="nv">docker</span><span class="w"> </span><span class="k">exec</span><span class="w"> </span><span class="nv">bb241e2e020b</span><span class="w"> </span><span class="nv">sh</span><span class="w"> </span><span class="o">-</span><span class="nv">c</span><span class="w"> </span><span class="s2">"echo \)\; >> config/test.php"</span><span class="w"></span>
<span class="nv">docker</span><span class="w"> </span><span class="k">exec</span><span class="w"> </span><span class="nv">bb241e2e020b</span><span class="w"> </span><span class="nv">sh</span><span class="w"> </span><span class="o">-</span><span class="nv">c</span><span class="w"> </span><span class="s2">"cat config/test.php"</span><span class="w"></span>
<span class="nv">docker</span><span class="w"> </span><span class="k">exec</span><span class="w"> </span><span class="nv">bb241e2e020b</span><span class="w"> </span><span class="nv">sh</span><span class="w"> </span><span class="o">-</span><span class="nv">c</span><span class="w"> </span><span class="s2">"cp config/config.php config/config.php.orig"</span><span class="w"></span>
<span class="nv">docker</span><span class="w"> </span><span class="k">exec</span><span class="w"> </span><span class="nv">bb241e2e020b</span><span class="w"> </span><span class="nv">sh</span><span class="w"> </span><span class="o">-</span><span class="nv">c</span><span class="w"> </span><span class="s2">"cp config/test.php config/config.php "</span><span class="w"></span>
</code></pre></div>
<p>I added the line to the a copy of the file and finally </p>
<div class="highlight"><pre><span></span><code>docker-compose stop && docker-compose up -d
</code></pre></div>
<p>to restart the container without building it.</p>
<p>In the end it worked and I am now able to login with the desktop clients and mobile app.</p>Goodbye Atom2022-11-04T00:11:00+01:002022-11-04T00:25:11+01:00Gianlucatag:devel.grys.it,2022-11-04:/goodbye-atom.html<p>And so Atom was retired from its authors. It was a nice editor. Hope it will not missed too much</p>Small update to myutils2022-03-13T18:27:00+01:002022-03-13T18:30:22+01:00Gianlucatag:devel.grys.it,2022-03-13:/small-update-to-myutils.html<p>A small upgrade to the myutils collection. Just updated the "blog_resize_images"
to accept both a list of files that a directory as input. Can be usefull to quick
convert just an image in a directory with more not related files.</p>
<p>Also added a version to it, 0.2 as for …</p><p>A small upgrade to the myutils collection. Just updated the "blog_resize_images"
to accept both a list of files that a directory as input. Can be usefull to quick
convert just an image in a directory with more not related files.</p>
<p>Also added a version to it, 0.2 as for now.</p>Leaving Nextcloud2022-02-01T21:34:00+01:002022-02-01T22:21:55+01:00Gianlucatag:devel.grys.it,2022-02-01:/leaving-nextcloud.html<p>After many years of use, I finally say the last goodbye to Nextcloud, the self hosted solution
I used to sync my calendar, files and little more.</p>
<p>I was using Nextcloud from before the fork from Owncloud, so I can say it was a long ride, but in the end …</p><p>After many years of use, I finally say the last goodbye to Nextcloud, the self hosted solution
I used to sync my calendar, files and little more.</p>
<p>I was using Nextcloud from before the fork from Owncloud, so I can say it was a long ride, but in the end the conclusion arrived.</p>
<p>Why to change ? Well, basically because I am sick and tired to fight with its update process. At the beginning I was using a custom installation and the update was a pain. Then I switched to use the package provided by <a href="https://www.archlinux.org">Archlinux</a> but the problems were not solved.</p>
<p>The biggest one is that PHP 8.x was non supported for a couple of major release (21 and 22 IIRC) and since the server also hosted some public sites, it became increasly harder to keep update the system <em>and</em> Nextcloud. In the end I was locked to an old 21.x release. <br>
But as the new release come out, I realise it will became harder the more I wait to upgrade. So I removed the lock on the Nextcloud package in the pacman.conf file and run an update, after all what can go wrong ? Well, everything.</p>
<p>Not only you cannot upgrade from more than 1 major release back (for example, 21.x->22.x and not 21.x->23.x), which I can somewhat understand, but even the upgrade process is broken, so after upgrading from 21.x to 22.x and from 22.x to 23.x, I ended up in and endless loop of "this app need to be upgraded"/launch the upgrade process/success/redirect back to step 1.<br>
Not what a user (even an advanced one) want. </p>
<p>After a lot of work and attempts, which nearly cost me all the Wordpress installations, I finally give up and decided get it out of the way. <br>
BTW, I don't really understand how every Open Source project tends to became a nightmare to use if not on the developer's machine (yes, akonady, I am also looking at you) once it became a little more complex. Or better, I get that it is a lot more fun to add new features, but come on, a software should be usable even from the average user, especially in a default configuration.</p>
<p>Anyway, with Nextcloud out the game I still need to have a way to sync my calendars and the files, but what to use ? <br>
My requirements are failry simple: sync the files from the phone and a couple of PC, one of which is dualboot Linux/Win and just keep track of my calendars.</p>
<p>Sooo, enter <a href="https://radicale.org/v3.html">Radicale</a> and <a href="https://syncthing.net/">Synchthing</a></p>
<p><a href="https://radicale.org/v3.html">Radicale</a> is a CalDav/CardDav server to allow to sync calendars and contacts.</p>
<p><a href="https://syncthing.net/">Synchthing</a> is a file synchronization server/client that allow you to keep one or more directories on different systems synched. It has also and Android app.</p>
<p>Both of them are pretty simple to set up and pretty fast, the only downside is that there is not a "real" web interface to access the data (but there is one to configure them), which can be a problem with the calendar <em>if</em> you need to add something without using your phone (well, it can be an idea for a little desktop app) or some other already configured software.</p>Porting to Qt62021-12-30T23:33:00+01:002021-12-30T23:47:59+01:00Gianlucatag:devel.grys.it,2021-12-30:/porting-to-qt6.html<p>So I finally started (about time) porting my Qt projects to Qt6. The first one is <a href="https://gitlab.com/mgian/nmsmodmanager">NoManSky Mod Mannager</a> which is a simple mod manager for the No Man's Sky game. It all started because a friend asked a couple of new features, so I take the occasion to update …</p><p>So I finally started (about time) porting my Qt projects to Qt6. The first one is <a href="https://gitlab.com/mgian/nmsmodmanager">NoManSky Mod Mannager</a> which is a simple mod manager for the No Man's Sky game. It all started because a friend asked a couple of new features, so I take the occasion to update the Qt installation to the newest LTS (6.2.2) and tried to recompile it. Since the program was simple I had no problem here.</p>
<p>The next project I ported is <a href="https://www.bulbcalculator.com">bulbcalculator</a>, and here I got a lot of work to do. So I created a new branch (Qt6) and started working on it. The two biggest problems were with the OpenGL Widget and with the printer (something changed here) but in the end I was able to compile it and have it working. It will live on this branch for some time until I completed the tests (printing is the most important one)</p>
<p>The next projects to port will be a Python one, but for now I am focused on the two above.</p>Post to Discord from Wordpress2021-03-07T23:57:00+01:002021-03-08T15:43:02+01:00Gianlucatag:devel.grys.it,2021-03-07:/post-to-discord-from-wordpress.html<p>The <a href="https://www.bulbcalculator.com">bulbcalculator project</a> has now a Discord
server, hoping it would be used sometimes in the future. Anyway, just to play around,
I wanted to be able to post on a channel of the Discord server when posting something on the project site,
basically announces.</p>
<p>It turned out that the …</p><p>The <a href="https://www.bulbcalculator.com">bulbcalculator project</a> has now a Discord
server, hoping it would be used sometimes in the future. Anyway, just to play around,
I wanted to be able to post on a channel of the Discord server when posting something on the project site,
basically announces.</p>
<p>It turned out that the process is really simple, you just need to set a webhook on the Discord server, tied to the channel you want, and set a simple plugin on the Wordpress site.</p>
<p>Now, for the webhook on Discord there was a lot of documentation, so it is really simple. For the Wordpress side things are a little less documented, but I had the luck to find <a href="https://badecho.com/index.php/2020/10/20/automatically-posting-wordpress-posts-to-discord/">this plugin</a> from Matt Weber that does just what I need. The only problem from my point of view is that it forward to Discord every post while I just wanted to forward post form a certain category.</p>
<p>Luckily Matt's plugin is really simple and so I just needed to extend it to consider the category of the post, which after some tinkering ended up to be really simple. The end result is <a href="https://gitlab.com/mgian/wp2discord/">wp2discord</a>, a Wordpress plugin which forward the post of a certain category to a given Discord channel (on a given server of course). The only thins you need to configure is the webhook id and input the category for which it must be done.</p>
<p>The plugin is basically a copy of the original work from Matt, to which I give credit and I must thank a lot, with two important changes:</p>
<ul>
<li>
<p>the first one is the different "action" it intercept, the original get the <code>transition_post_status</code> action, while I ended up intercepting the <code>publish_post</code> one.</p>
</li>
<li>
<p>as a consequence of the different action intercepted, I am now able to get also the category (or categories) of the post to check if the correct one is present</p>
</li>
</ul>
<p>The plugin then loop over every category of the post and if it find the correct one is found the post is forwarded as a message to the Discord channel.<br>
The message itself contain the title and the permalink of the post.</p>
<p>The only thing I'd like to add is to be able to post to different channels based on the category of the post, but is not really urgent for now.</p>Merging git repositories2021-02-02T23:10:00+01:002021-02-02T23:33:10+01:00Gianlucatag:devel.grys.it,2021-02-02:/merging-git-repositories.html<p>For a project, I decided that can be a good idea to merge a couple of repositories to have a single point where to put all the code, issues, wiki and so on.</p>
<p>I later abandoned the idea, since it not came out as good as I was thinking, but …</p><p>For a project, I decided that can be a good idea to merge a couple of repositories to have a single point where to put all the code, issues, wiki and so on.</p>
<p>I later abandoned the idea, since it not came out as good as I was thinking, but in the end I have done it, so why not to share how to do it ?</p>
<p>The main point was that I'd liked to not lose the commit history of the repos I was merging, so I should find some way to merge even these.</p>
<p>Of course a simple copy of the code does not work, since you loose the commit history.<br>
Luckily git offer a way to do it anyway.</p>
<p>The method I used, and later found in a lot of places so nothing new, is to decide which is the main repository where to add the others and then use the merge command.</p>
<p>Assuming that <code>repoA</code> is the main repository with a project caller <code>ProjectA</code> and <code>repoB</code> is the one I want to add with a project called <code>ProjectB</code>, here is the command to use:</p>
<div class="highlight"><pre><span></span><code>git remote add repoBRemote repoBPath
git fetch repoBRemote
git checkout -b ProjectB repoB/master
mkdir ProjectB
git mv <span class="o">[</span>everything <span class="k">in</span> the procject<span class="o">]</span> ProjectB
git commit -m <span class="o">[</span>commit message<span class="o">]</span>
git checkout master
git merge ProjectB
git commit
git push
git remote rm repoBRemote
git branch -d ProjectB
</code></pre></div>
<p>The end result is a repository with this structure</p>
<div class="highlight"><pre><span></span><code>|
|--- ProjectA
| |...
|
|--- ProjectB
| |...
</code></pre></div>
<p>and the commit history of both of them.</p>Making the MiniBookDB database public take 22021-01-20T23:10:00+01:002021-03-08T15:04:54+01:00Gianlucatag:devel.grys.it,2021-01-20:/making-the-minibookdb-database-public-take-2.html<p>In the quest to make the MiniBookDb database readable from outside my home network, I tried to use a microservice in Pythn/Flask.<br>
While the approach work, I had the problem that the same site name is resolved with different IP depending on where I am: on my private network …</p><p>In the quest to make the MiniBookDb database readable from outside my home network, I tried to use a microservice in Pythn/Flask.<br>
While the approach work, I had the problem that the same site name is resolved with different IP depending on where I am: on my private network the site name is resolved with an private IP, on the outside it is solved as a public IP. </p>
<p><em>The probem</em><br>
On my private network, I also run the DNS, so that I can assign a specific IP to MiniBookDB on the Raspberry, so since the site is accessible with the same name both from outside and inside the private network, when the Raspberry call the microservice on the public server, in the end it call itself and fail.</p>
<p>Since I don't want to use different site name, I had to let go the microservice and use another way.</p>
<p><em>The solution</em><br>
Remembering how I deploy this site (and the other one) I decide to use git and the old good cron, with some python magic.</p>
<p>The pyhton magic is just a script that execute some simple actions:
- extract all the books from the MongoDB, selecting only the needed fields
- store them in a SQLite file
- generate the HTML files from the SQLite db
- commit them to a git repository</p>
<p>Once the file are pushed to the git repository which is on the public server, an hook extract the HTML files and copy them in the correct directory where the site live.</p>
<p>The operation is executed every day at midnight using a cron job on the Raspberry.</p>
<p>All the sensible operations are done on the Raspberry, so inside my private network and I ditched also the need for authentication when calling the microservice, since it is handled by git using the usual ssh key.</p>
<p>The hook on the server is pretty simple, copied and adapted from the one I use for this site.</p>
<p><em>The result</em><br>
After the initial problems in the tests, the system work very well. The only downside is that the public pages are update once a day, but that is acceptable.</p>Server migration2021-01-18T22:38:00+01:002021-02-02T23:16:16+01:00Gianlucatag:devel.grys.it,2021-01-18:/server-migration.html<p>So, after many years, I left Linode to move to an European VPS provider, Transip.</p>
<p>Why ? Well, first thing is the price. For a little less, I got something more in term of
disk space (both are ssd, but the new VPS as almost double disk space than the old …</p><p>So, after many years, I left Linode to move to an European VPS provider, Transip.</p>
<p>Why ? Well, first thing is the price. For a little less, I got something more in term of
disk space (both are ssd, but the new VPS as almost double disk space than the old one) and
not counting the backup and snapshot already in the price and a 25% increase in the transfer cap.</p>
<p>Plus is an European provider even if it is true that the old Linode VPS was in an European datacenter (Germany).</p>
<p>Bonus, I also bought a second IP address, to separate my personal data from the site I host.</p>
<p>To match the new server configuration, I should have migrated to a bigger VPS on Linode, which double the
price which is a no go. </p>
<p>Additionally, I also was able to use a special offer, so for the first months the price is even
lower, and with what I am saving from the VPS I can pay for an account on ProtonMail, which is nice.</p>
<p>The biggest problem, since the server hosts also a bunch of sites, was the DNS update and the migration
of this domain, which used the Linode's DNS and now the registar's ones.</p>
<p>The installation was simple, I just have to follow the docs provided by TransIp, which guide you step by step
on what to do to install one of the available Linux distro and the migration of the sites and service
was smooth, having both VPS running simplified a lot of things, principally the service
configuration, even if I decided to start from scratch and not just copy the old configuration files.</p>
<p>All in all I am satisfied with the new server and I am also saving some bucks :-D</p>Multiple IP addesses on Archlinux2021-01-13T00:00:00+01:002021-01-13T18:55:38+01:00Gianlucatag:devel.grys.it,2021-01-13:/multiple-ip-addesses-on-archlinux.html<p>That's another post that is here more to be a reminder to me that to be really usefull or add important informations.</p>
<p>Since I am migrating to a new VPS and I'd like to keep my personal stuff separated from the other sites I hosted on my server, I decide …</p><p>That's another post that is here more to be a reminder to me that to be really usefull or add important informations.</p>
<p>Since I am migrating to a new VPS and I'd like to keep my personal stuff separated from the other sites I hosted on my server, I decide to get 2 IP addresses to use.</p>
<p>Then the problem is how to use both of them: well, really simple.
The new installation uses Archlinux and the default systemd-networkd, so once I created the file for the interface, I just needed to add another <code>Address =</code> line to it to use the second IP.</p>
<p>The end results is something like:</p>
<div class="highlight"><pre><span></span><code><span class="k">[Network]</span><span class="w"></span>
<span class="na">Address</span><span class="o">=</span><span class="s">your_first_ip</span><span class="w"></span>
<span class="na">Address</span><span class="o">=</span><span class="s">your_second_ip</span><span class="w"></span>
<span class="na">Gateway</span><span class="o">=</span><span class="s">your_gateway</span><span class="w"></span>
<span class="na">DNS</span><span class="o">=</span><span class="s">your_dns</span><span class="w"></span>
</code></pre></div>
<p>and just restart. That's all. Really.
(I was afraid it would be way more complicated to be honest)</p>ldconfig and custom directories2020-06-20T00:00:00+02:002020-06-20T17:18:45+02:00Gianlucatag:devel.grys.it,2020-06-20:/ldconfig-and-custom-directories.html<p>This is more a reminder to myself than a new discovery. </p>
<p>To add a new directory where put the .so libraries and be able to use them, just add a new file with the path(s) in the <code>/etc/ld.so.conf.d</code> directory and run <code>ldconfig</code></p>Splitting Pelican pages list2020-06-20T00:00:00+02:002020-06-20T17:14:38+02:00Gianlucatag:devel.grys.it,2020-06-20:/splitting-pelican-pages-list.html<p>For another site/blog I write, with <a href="https://blog.getpelican.com/">Pelican</a> like this blog, I had the necessity to split the list of the site's pages into 2 indipendent lists. This because some pages contains something like the datasheet of a scale model while others are normal pages (links, about and so on …</p><p>For another site/blog I write, with <a href="https://blog.getpelican.com/">Pelican</a> like this blog, I had the necessity to split the list of the site's pages into 2 indipendent lists. This because some pages contains something like the datasheet of a scale model while others are normal pages (links, about and so on)</p>
<p>After looking for a Pelican's theme that do it natively without finding one, I gave up and hacked a solution that seems to work reasonably well. As bonus it is possible, given the necessary modification to the theme, split the list in more than 2 lists.</p>
<p>Without an in-deep explanation of how Pelican work the solution is somewhat simple.<br>
In every page I put a <code>page_order: n</code> directive, then in the theme code that render the list I checked the value and acted as necessary.</p>
<div class="highlight"><pre><span></span><code><span class="cp">{%</span> <span class="k">if</span> <span class="nv">pages</span> <span class="cp">%}</span>
<span class="nt"><nav></span>
<span class="nt"><ul</span> <span class="na">class=</span><span class="s">"list"</span><span class="nt">></span>
<span class="nt"><font</span> <span class="na">size=</span><span class="s">"+2"</span><span class="nt">><b></span>Schede modelli<span class="nt"></b></font></span>
<span class="cp">{%</span> <span class="k">if</span> <span class="k">not</span> <span class="nv">PAGES_SORT_ATTRIBUTE</span> -<span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">set</span> <span class="nv">PAGES_SORT_ATTRIBUTE</span> <span class="o">=</span> <span class="s1">'title'</span> <span class="cp">%}</span>
<span class="cp">{%</span>- <span class="k">endif</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">page</span> <span class="k">in</span> <span class="nv">pages</span><span class="o">|</span><span class="nf">sort</span><span class="o">(</span><span class="nv">attribute</span><span class="o">=</span><span class="nv">PAGES_SORT_ATTRIBUTE</span><span class="o">)</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">page.page_order</span> <span class="o">==</span> <span class="s1">'1'</span> -<span class="cp">%}</span>
<span class="nt"><li><a</span> <span class="na">href=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/</span><span class="cp">{{</span> <span class="nv">page.url</span> <span class="cp">}}{%</span> <span class="k">if</span> <span class="k">not</span> <span class="nv">DISABLE_URL_HASH</span> <span class="cp">%}</span><span class="s">#</span><span class="cp">{{</span> <span class="nv">page.slug</span> <span class="cp">}}{%</span> <span class="k">endif</span> <span class="cp">%}</span><span class="s">"</span><span class="nt">></span><span class="cp">{{</span> <span class="nv">page.title</span> <span class="cp">}}</span><span class="nt"></a></li></span>
<span class="cp">{%</span>- <span class="k">endif</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="nt"></ul></span>
<span class="nt"><ul</span> <span class="na">class=</span><span class="s">"list"</span><span class="nt">></span>
<span class="nt"><font</span> <span class="na">size=</span><span class="s">"+2"</span><span class="nt">><b></span>Meta<span class="nt"></b></font></span>
<span class="cp">{%</span> <span class="k">if</span> <span class="k">not</span> <span class="nv">PAGES_SORT_ATTRIBUTE</span> -<span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">set</span> <span class="nv">PAGES_SORT_ATTRIBUTE</span> <span class="o">=</span> <span class="s1">'title'</span> <span class="cp">%}</span>
<span class="cp">{%</span>- <span class="k">endif</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">page</span> <span class="k">in</span> <span class="nv">pages</span><span class="o">|</span><span class="nf">sort</span><span class="o">(</span><span class="nv">attribute</span><span class="o">=</span><span class="nv">PAGES_SORT_ATTRIBUTE</span><span class="o">)</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">page.page_order</span> <span class="o">==</span> <span class="s1">'2'</span> -<span class="cp">%}</span>
<span class="nt"><li><a</span> <span class="na">href=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/</span><span class="cp">{{</span> <span class="nv">page.url</span> <span class="cp">}}{%</span> <span class="k">if</span> <span class="k">not</span> <span class="nv">DISABLE_URL_HASH</span> <span class="cp">%}</span><span class="s">#</span><span class="cp">{{</span> <span class="nv">page.slug</span> <span class="cp">}}{%</span> <span class="k">endif</span> <span class="cp">%}</span><span class="s">"</span><span class="nt">></span><span class="cp">{{</span> <span class="nv">page.title</span> <span class="cp">}}</span><span class="nt"></a></li></span>
<span class="cp">{%</span>- <span class="k">endif</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="nt"></ul></span>
<span class="nt"></nav></span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
</code></pre></div>
<p>(the code is from the theme I use, <a href="https://github.com/alexandrevicenzi/flex">Flex</a>)</p>
<p>It is simple to see how it works: since every page has a <code>page_order: n</code> I just needed to duplicate the rendering code for the pages to be able to have 2 lists and in every list I check for a specific value of <code>n</code> and add the list item only if I the page has the correct <code>page_order</code> value.<br>
As you can see, to have more than 2 lists you just need to duplicate the code, one for every list you want, and update the pages. </p>
<p>It is possible also to see that I logically split the pages list from the links list and done some minor adjustement to the theme, but nothing fancy</p>
<p>Probably it is not the correct way to do it, the <code>page_order</code> directive has another use, but since I don't wanted to build a new plugin, I decided that for my objective it was enough.</p>Resizing images2020-04-12T21:45:00+02:002020-04-12T21:58:42+02:00Gianlucatag:devel.grys.it,2020-04-12:/resizing-images.html<p>For the my other blog about models and hobby, I frequently need to resize a batch of images. Using ImageMagik is possible, but after a couple images it become boring and time consuming.</p>
<p>So, being stuck at home, I came up with a small python script which use the Python …</p><p>For the my other blog about models and hobby, I frequently need to resize a batch of images. Using ImageMagik is possible, but after a couple images it become boring and time consuming.</p>
<p>So, being stuck at home, I came up with a small python script which use the Python Image Library (in the Pillow fork) and the <a href="https://pypi.org/project/python-resize-image/">python-resize-image module.</a></p>
<p>The script is really simple and has the new size hardcoded to 1024x768, but for now it does what I need</p>
<div class="highlight"><pre><span></span><code><span class="c1"># This project is licensed under the GNU General Public License v3.0</span>
<span class="c1"># Copyright (C) 2020 Gianluca Montecchi (gian@grys.it)</span>
<span class="c1">#</span>
<span class="c1"># A small script to resize all the images in the given directory base on the</span>
<span class="c1"># Python Image Library (Pillow) and the resizeimage module</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">from</span> <span class="nn">PIL</span> <span class="kn">import</span> <span class="n">Image</span>
<span class="kn">from</span> <span class="nn">resizeimage</span> <span class="kn">import</span> <span class="n">resizeimage</span>
<span class="k">def</span> <span class="nf">usage</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"""</span>
<span class="s2">Usage:</span>
<span class="s2"> blog_resize_images input_dir [output_dir]</span>
<span class="s2"> input_dir -> directory where the original file are located</span>
<span class="s2"> output_dir -> directory where to write the resized files</span>
<span class="s2"> """</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">usage</span><span class="p">()</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
<span class="n">INPUT_DIR</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">></span> <span class="mi">2</span><span class="p">:</span>
<span class="n">usage</span><span class="p">()</span>
<span class="n">files</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">INPUT_DIR</span><span class="p">)</span>
<span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">files</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Resizing file: "</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="s2">"r+b"</span><span class="p">)</span> <span class="k">as</span> <span class="n">FI</span><span class="p">:</span>
<span class="k">with</span> <span class="n">Image</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">f</span><span class="p">)</span> <span class="k">as</span> <span class="n">image</span><span class="p">:</span>
<span class="n">cover</span> <span class="o">=</span> <span class="n">resizeimage</span><span class="o">.</span><span class="n">resize_contain</span><span class="p">(</span><span class="n">image</span><span class="p">,</span> <span class="p">[</span><span class="mi">1024</span><span class="p">,</span><span class="mi">768</span><span class="p">])</span>
<span class="n">cover</span> <span class="o">=</span> <span class="n">cover</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s2">"RGB"</span><span class="p">)</span>
<span class="n">cover</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">image</span><span class="o">.</span><span class="n">format</span><span class="p">)</span>
</code></pre></div>
<p>The script is hosted on <a href="https://gitlab.com/mgian/myutils">Gitlab in the myutils repo</a>.</p>BulbCalculator 3.1.02020-03-23T22:47:00+01:002020-06-20T16:44:19+02:00Gianlucatag:devel.grys.it,2020-03-23:/bulbcalculator-310.html<p>A new release of BulbCalculator is out.<br>
The 3.1.0 is a minor release with a very short changelog
* Fixed the STL Ascii export
* Removed the STL Binary export, at least for now.</p>
<p>The first is a bugfix to the STL export which render the exported file basically
unusable …</p><p>A new release of BulbCalculator is out.<br>
The 3.1.0 is a minor release with a very short changelog
* Fixed the STL Ascii export
* Removed the STL Binary export, at least for now.</p>
<p>The first is a bugfix to the STL export which render the exported file basically
unusable.<br>
The second change remove the option to export the binary version of the STL file. This
since for now I have no way to test it. Given that basically all software accept the
Ascii version, I don't think to add (and make it working) this option anytime soon, if ever.</p>Building BulbCalculator windows setup2020-02-22T08:33:00+01:002020-02-22T09:50:12+01:00Gianlucatag:devel.grys.it,2020-02-22:/building-bulbcalculator-windows-setup.html<p>Well, after too much time, I decided to make a binary release for windows of
<a href="https://www.bulbcalculator.com">BulbCalculator</a> and prepare two setups, one for 64 bit and one for 32 bit (if someone still use it).</p>
<p>After trying to use the Qt Installation framework, failing to build a working setup, I switched …</p><p>Well, after too much time, I decided to make a binary release for windows of
<a href="https://www.bulbcalculator.com">BulbCalculator</a> and prepare two setups, one for 64 bit and one for 32 bit (if someone still use it).</p>
<p>After trying to use the Qt Installation framework, failing to build a working setup, I switched back to <a href="https://nsis.sourceforge.io/Main_Page">NSIS</a>, which was used to build a very old setup for bulbcalculator.</p>
<p>After some tweaking of the old .nsi file, I got two more or less working setup for both win32 and win64.</p>
<p>But how to do it ?<br>
Well, the procedure is reasonably easy.</p>
<p>The first step is to build the package for the target platform (you don't say, right ?). After this, what you need to do is to copy all the dependencies of your executable. To do this there is a nice program to find (almost) all of them: <em>windeployqt</em>. Just call it with your executable as argument and it will copy all the needed modules and Dll in the executable directory. Please not that you need to use the correct (32 or 64 bit) version, else it will copy the wrong files.</p>
<p>After that I just moved all the files to a working directory, just for convenience, and tried to run from here. This allow to discover if there are some other missing files. Onche the executable works fine, you are ready to build the setup package.</p>
<p>To do this, you need to write a NSIS script to look something like this:</p>
<p><em>bulbcalculator_setup64.nsi</em></p>
<div class="highlight"><pre><span></span><code><span class="p">;</span><span class="n">BulbCalculator</span><span class="w"> </span><span class="s">Installer</span><span class="w"></span>
<span class="sx">!define PRODUCT_NAME "BulbCalculator"</span><span class="w"></span>
<span class="sx">!define PRODUCT_VERSION "3.0.0"</span><span class="w"></span>
<span class="sx">!define PRODUCT_DIR_REGKEY "Software\${PRODUCT_NAME}"</span><span class="w"></span>
<span class="n">Name</span><span class="w"> </span><span class="s">"${PRODUCT_NAME}</span><span class="w"> </span><span class="s">${PRODUCT_VERSION}"</span><span class="w"></span>
<span class="n">OutFile</span><span class="w"> </span><span class="s">"bulbcalculator-${PRODUCT_VERSION}-win64.exe"</span><span class="w"></span>
<span class="n">SetCompressor</span><span class="w"> </span><span class="s">lzma</span><span class="w"></span>
<span class="n">InstallDir</span><span class="w"> </span><span class="s">"$PROGRAMFILES\${PRODUCT_NAME}"</span><span class="w"></span>
<span class="n">InstallDirRegKey</span><span class="w"> </span><span class="s">HKCU</span><span class="w"> </span><span class="s">"${PRODUCT_DIR_REGKEY}"</span><span class="w"> </span><span class="s">""</span><span class="w"></span>
<span class="sx">!include "MUI.nsh"</span><span class="w"></span>
<span class="sx">!define MUI_ABORTWARNING</span><span class="w"></span>
<span class="sx">!insertmacro MUI_PAGE_LICENSE "COPYING"</span><span class="w"></span>
<span class="sx">!insertmacro MUI_PAGE_COMPONENTS</span><span class="w"></span>
<span class="sx">!insertmacro MUI_PAGE_DIRECTORY</span><span class="w"></span>
<span class="sx">!insertmacro MUI_PAGE_INSTFILES</span><span class="w"></span>
<span class="sx">!define MUI_FINISHPAGE_RUN "$INSTDIR\bulbcalculator.exe"</span><span class="w"></span>
<span class="sx">!define MUI_FINISHPAGE_LINK "Visit the BulbCalculator website"</span><span class="w"></span>
<span class="sx">!define MUI_FINISHPAGE_LINK_LOCATION "http://www.bulbcalculator.com/"</span><span class="w"></span>
<span class="sx">!insertmacro MUI_PAGE_FINISH</span><span class="w"></span>
<span class="sx">!insertmacro MUI_UNPAGE_CONFIRM</span><span class="w"></span>
<span class="sx">!insertmacro MUI_UNPAGE_INSTFILES</span><span class="w"></span>
<span class="sx">!insertmacro MUI_LANGUAGE "English"</span><span class="w"></span>
<span class="n">Section</span><span class="w"> </span><span class="s">"BulbCalculator"</span><span class="w"> </span><span class="s">SecBulbCalculator</span><span class="w"></span>
<span class="w"> </span><span class="n">SectionIn</span><span class="w"> </span><span class="n">RO</span><span class="w"></span>
<span class="w"> </span><span class="n">SetOutPath</span><span class="w"> </span><span class="s">"$INSTDIR"</span><span class="w"></span>
<span class="w"> </span><span class="n">WriteRegStr</span><span class="w"> </span><span class="n">HKCU</span><span class="w"> </span><span class="s">"${PRODUCT_DIR_REGKEY}"</span><span class="w"> </span><span class="s">""</span><span class="w"> </span>$<span class="n">INSTDIR</span><span class="w"></span>
<span class="w"> </span><span class="n">File</span><span class="w"> </span><span class="n">setup_64</span><span class="o">\</span><span class="n">bulbcalculator</span><span class="p">.</span><span class="n">exe</span><span class="w"></span>
<span class="w"> </span><span class="n">File</span><span class="w"> </span><span class="n">setup_64</span><span class="o">\*</span><span class="p">.</span><span class="n">dll</span><span class="w"></span>
<span class="w"> </span><span class="n">File</span><span class="w"> </span><span class="n">COPYING</span><span class="w"></span>
<span class="w"> </span><span class="n">File</span><span class="w"> </span><span class="o">/</span><span class="n">r</span><span class="w"> </span><span class="n">setup_64</span><span class="o">\</span><span class="n">iconengines</span><span class="w"></span>
<span class="w"> </span><span class="n">File</span><span class="w"> </span><span class="o">/</span><span class="n">r</span><span class="w"> </span><span class="n">setup_64</span><span class="o">\</span><span class="n">styles</span><span class="w"></span>
<span class="w"> </span><span class="n">File</span><span class="w"> </span><span class="o">/</span><span class="n">r</span><span class="w"> </span><span class="n">setup_64</span><span class="o">\</span><span class="n">translations</span><span class="w"></span>
<span class="w"> </span><span class="n">File</span><span class="w"> </span><span class="o">/</span><span class="n">r</span><span class="w"> </span><span class="n">setup_64</span><span class="o">\</span><span class="n">imageformats</span><span class="w"></span>
<span class="w"> </span><span class="n">File</span><span class="w"> </span><span class="o">/</span><span class="n">r</span><span class="w"> </span><span class="n">setup_64</span><span class="o">\</span><span class="n">platforms</span><span class="w"></span>
<span class="w"> </span><span class="n">File</span><span class="w"> </span><span class="o">/</span><span class="n">r</span><span class="w"> </span><span class="n">setup_64</span><span class="o">\</span><span class="n">printsupport</span><span class="w"></span>
<span class="w"> </span><span class="n">WriteUninstaller</span><span class="w"> </span><span class="s">"$INSTDIR\uninstall.exe"</span><span class="w"></span>
<span class="n">SectionEnd</span><span class="w"></span>
<span class="s">Section</span><span class="w"> </span><span class="s">"Create</span><span class="w"> </span><span class="s">Desktop</span><span class="w"> </span><span class="s">Shortcut"</span><span class="w"> </span><span class="s">DescShortcut</span><span class="w"></span>
<span class="w"> </span><span class="n">CreateShortCut</span><span class="w"> </span><span class="s">"$DESKTOP\${PRODUCT_NAME}.lnk"</span><span class="w"> </span><span class="s">"$INSTDIR\bulbcalculator.exe"</span><span class="w"> </span><span class="s">""</span><span class="w"> </span><span class="s">"$INSTDIR\share\images\bulbcalculator.ico"</span><span class="w"></span>
<span class="n">SectionEnd</span><span class="w"></span>
<span class="s">Section</span><span class="w"> </span><span class="s">"Start</span><span class="w"> </span><span class="s">Menu</span><span class="w"> </span><span class="s">Shortcuts"</span><span class="w"> </span><span class="s">SecShortcut</span><span class="w"></span>
<span class="w"> </span><span class="n">CreateDirectory</span><span class="w"> </span><span class="s">"$SMPROGRAMS\${PRODUCT_NAME}"</span><span class="w"></span>
<span class="w"> </span><span class="n">CreateShortCut</span><span class="w"> </span><span class="s">"$SMPROGRAMS\${PRODUCT_NAME}\BulbCalculator.lnk"</span><span class="w"> </span><span class="s">"$INSTDIR\bulbcalculator.exe"</span><span class="w"> </span><span class="s">""</span><span class="w"> </span><span class="s">"$INSTDIR\share\images\bulbcalculator.ico"</span><span class="w"></span>
<span class="w"> </span><span class="n">CreateShortCut</span><span class="w"> </span><span class="s">"$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk"</span><span class="w"> </span><span class="s">"$INSTDIR\uninstall.exe"</span><span class="w"></span>
<span class="n">SectionEnd</span><span class="w"></span>
<span class="s">!insertmacro</span><span class="w"> </span><span class="s">MUI_FUNCTION_DESCRIPTION_BEGIN</span><span class="w"></span>
<span class="w"> </span>!<span class="n">insertmacro</span><span class="w"> </span><span class="n">MUI_DESCRIPTION_TEXT</span><span class="w"> </span>$<span class="p">{</span><span class="n">SecBulbCalculator</span><span class="p">}</span><span class="w"> </span><span class="s">"Installs BulbCalculator."</span><span class="w"></span>
<span class="w"> </span>!<span class="n">insertmacro</span><span class="w"> </span><span class="n">MUI_DESCRIPTION_TEXT</span><span class="w"> </span>$<span class="p">{</span><span class="n">DescShortcut</span><span class="p">}</span><span class="w"> </span><span class="s">"Installs BulbCalculator."</span><span class="w"></span>
<span class="w"> </span>!<span class="n">insertmacro</span><span class="w"> </span><span class="n">MUI_DESCRIPTION_TEXT</span><span class="w"> </span>$<span class="p">{</span><span class="n">SecShortcut</span><span class="p">}</span><span class="w"> </span><span class="s">"Adds share to your start menu for easy access."</span><span class="w"></span>
<span class="sx">!insertmacro MUI_FUNCTION_DESCRIPTION_END</span><span class="w"></span>
<span class="n">Section</span><span class="w"> </span><span class="s">"Uninstall"</span><span class="w"></span>
<span class="w"> </span><span class="n">DeleteRegKey</span><span class="w"> </span><span class="n">HKCR</span><span class="w"> </span><span class="s">"BulbCalculator.blb"</span><span class="w"></span>
<span class="w"> </span><span class="n">DeleteRegKey</span><span class="w"> </span><span class="n">HKCR</span><span class="w"> </span><span class="s">".blb"</span><span class="w"></span>
<span class="w"> </span><span class="n">DeleteRegKey</span><span class="w"> </span><span class="n">HKCU</span><span class="w"> </span><span class="s">"${PRODUCT_DIR_REGKEY}"</span><span class="w"></span>
<span class="w"> </span><span class="n">RMDir</span><span class="w"> </span><span class="o">/</span><span class="n">r</span><span class="w"> </span><span class="s">"$SMPROGRAMS\${PRODUCT_NAME}"</span><span class="w"></span>
<span class="w"> </span><span class="n">Delete</span><span class="w"> </span><span class="s">"$INSTDIR\bulbcalculator.exe"</span><span class="w"></span>
<span class="w"> </span><span class="n">Delete</span><span class="w"> </span><span class="s">"$INSTDIR\*.dll"</span><span class="w"></span>
<span class="w"> </span><span class="n">Delete</span><span class="w"> </span><span class="s">"$INSTDIR\ChangeLog"</span><span class="w"></span>
<span class="w"> </span><span class="n">Delete</span><span class="w"> </span><span class="s">"$INSTDIR\COPYING"</span><span class="w"></span>
<span class="w"> </span><span class="n">Delete</span><span class="w"> </span><span class="s">"$INSTDIR\README"</span><span class="w"></span>
<span class="w"> </span><span class="n">RMDir</span><span class="w"> </span><span class="o">/</span><span class="n">r</span><span class="w"> </span><span class="s">"$INSTDIR\iconengines"</span><span class="w"></span>
<span class="w"> </span><span class="n">RMDir</span><span class="w"> </span><span class="o">/</span><span class="n">r</span><span class="w"> </span><span class="s">"$INSTDIR\styles"</span><span class="w"></span>
<span class="w"> </span><span class="n">RMDir</span><span class="w"> </span><span class="o">/</span><span class="n">r</span><span class="w"> </span><span class="s">"$INSTDIR\translations"</span><span class="w"></span>
<span class="w"> </span><span class="n">RMDir</span><span class="w"> </span><span class="o">/</span><span class="n">r</span><span class="w"> </span><span class="s">"$INSTDIR\imageformats"</span><span class="w"></span>
<span class="w"> </span><span class="n">RMDir</span><span class="w"> </span><span class="o">/</span><span class="n">r</span><span class="w"> </span><span class="s">"$INSTDIR\platforms"</span><span class="w"></span>
<span class="w"> </span><span class="n">RMDir</span><span class="w"> </span><span class="o">/</span><span class="n">r</span><span class="w"> </span><span class="s">"$INSTDIR\printsupport"</span><span class="w"></span>
<span class="w"> </span><span class="n">Delete</span><span class="w"> </span><span class="s">"$INSTDIR\uninstall.exe"</span><span class="w"></span>
<span class="w"> </span><span class="n">RMDir</span><span class="w"> </span><span class="s">"$INSTDIR"</span><span class="w"></span>
<span class="n">SectionEnd</span><span class="w"> </span>
</code></pre></div>
<p>This script refer to the 64 bit version, but it is the same for the 32 bit, just some different path.</p>
<p>After that, you just need to compile the NSIS script and if all goes well, you will obtain a setup to test.</p>Porting from PyQt5 to PySide2, take two2020-01-10T22:52:00+01:002020-01-10T23:39:54+01:00Gianlucatag:devel.grys.it,2020-01-10:/porting-from-pyqt5-to-pyside2-take-two.html<p>Of course, porting from PyQt5 to PySide2 any not trivial codebase like <a href="https://gitlab.com/mgian/punteggi">Punteggi</a> require some more work than what I needed to port <a href="https://gitlab.com/mgian/vtf">Vtf</a>.<br>
The big problem, since this port was done under Archlinux, was to install PySide2. The package that come with the distro are missing the pyside2-uic and …</p><p>Of course, porting from PyQt5 to PySide2 any not trivial codebase like <a href="https://gitlab.com/mgian/punteggi">Punteggi</a> require some more work than what I needed to port <a href="https://gitlab.com/mgian/vtf">Vtf</a>.<br>
The big problem, since this port was done under Archlinux, was to install PySide2. The package that come with the distro are missing the pyside2-uic and pyside2-rcc tools, which are necessary to build the <code>.ui</code> file for the gui and the resorces (icons, and so on). After digging some more, I just installed it using <code>pip3 install pyside2</code> which, while not installing from a repository package, do the work well.</p>
<p>The next problem was that, apparently, pyside2-uic can generate <code>.py</code> files with contains some syntax error, this render the usage of it useless, at least in this case.<br>
The error I got was very trivial:</p>
<div class="highlight"><pre><span></span><code><span class="go">File "MainWin.py", line 184</span>
<span class="go"> if (self.TW_Results.columnCount() < 1)</span>
<span class="go"> ^</span>
<span class="go">SyntaxError: invalid syntax</span>
</code></pre></div>
<p>derivating from this fragment of code:</p>
<div class="highlight"><pre><span></span><code><span class="k">if</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">TW_Results</span><span class="o">.</span><span class="n">columnCount</span><span class="p">()</span> <span class="o"><</span> <span class="mi">1</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">TW_Results</span><span class="o">.</span><span class="n">setColumnCount</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</code></pre></div>
<p><code>TW_Results</code> is a <code>QTableWidget</code> which is just created empty.
While this happen in a couple of places where there is a <code>QTableWidget</code>, I still don't understand the reason.</p>
<p>So the next step was to use directly the <code>.ui</code> file using the <code>QUiLoader</code> which work reasonably well, but it implies some more changes to the code, since this way you have not access to the Gui element directly.<br>
So when you need to access the gui objects, like a <code>QPushButton</code> to connect a slot to the <code>clicked()</code> signal, you need to go from this code:</p>
<div class="highlight"><pre><span></span><code><span class="bp">self</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">B_ImpostaDati</span><span class="p">,</span> <span class="n">SIGNAL</span><span class="p">(</span><span class="s2">"clicked()"</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">ImpostaDati</span><span class="p">)</span>
</code></pre></div>
<p>to this code:</p>
<div class="highlight"><pre><span></span><code><span class="bp">self</span><span class="o">.</span><span class="n">B_ImpostaDati</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">window</span><span class="o">.</span><span class="n">findChild</span><span class="p">(</span><span class="n">QPushButton</span><span class="p">,</span> <span class="s1">'B_ImpostaDati'</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">B_ImpostaDati</span><span class="o">.</span><span class="n">clicked</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">ImpostaDati</span><span class="p">)</span>
</code></pre></div>
<p>which is tedious if there are a lot of object you need to interact with.<br>
On the other hand this force you to set explicitly the items you want to use so, for example, if you don't need to use a <code>QLabel</code> you just don't instantiate a class member for it and the label remains somewhat "hidden" to the class code while still visible.</p>
<p>This was a more challenging port than the first one, adding also the fact that the code base was ported from Python2 to Python2.Nevertheless it is done and now it just need to be tested.</p>Porting from PyQt5 to PySide22020-01-07T23:14:00+01:002020-01-07T23:49:59+01:00Gianlucatag:devel.grys.it,2020-01-07:/porting-from-pyqt5-to-pyside2.html<p>After some years, I finally decide to port some (if not all, given time) my Python project from PyQt4 to PySide2.</p>
<p>The reason is that now PySide2 is the official port while some years ago PyQt was a better choice.</p>
<p>The first, just because is much more simple than the …</p><p>After some years, I finally decide to port some (if not all, given time) my Python project from PyQt4 to PySide2.</p>
<p>The reason is that now PySide2 is the official port while some years ago PyQt was a better choice.</p>
<p>The first, just because is much more simple than the others, is <a href="https://gitlab.com/mgian/vtf">Vtf</a>, which is a little tool to calculate the cutting speed for machine tools. given the number of teeth, the feed rate and few other tools parameters, it calculate the machine paramenter you can use.</p>
<p>Anyway, porting from PyQt5 to PySide2 was really simple: just modify the imports</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">PyQt5</span> <span class="kn">import</span> <span class="n">QtGui</span><span class="p">,</span> <span class="n">QtCore</span><span class="p">,</span> <span class="n">QtWidgets</span>
<span class="kn">from</span> <span class="nn">PySide2.QtWidgets</span> <span class="kn">import</span> <span class="n">QApplication</span>
<span class="kn">from</span> <span class="nn">PySide2.QtWidgets</span> <span class="kn">import</span> <span class="n">QLabel</span>
<span class="kn">from</span> <span class="nn">PySide2.QtWidgets</span> <span class="kn">import</span> <span class="n">QDialog</span>
</code></pre></div>
<p>and correct the code accordingly and the program run like before.</p>
<p>Then since Vtf use a .ui file for the gui and there is a Makefile to call the <code>uic</code> equivalent for Python, so in the Makefile I just swapper the relevant command from <code>pyuic5</code> to <code>pyside2-uic</code>.</p>
<p>That's all, at least for this project. <br>
As soon as I will port my other projects, maybe I will find some other tips or problem to port the code. I will see.</p>Making the MiniBookDB database public2020-01-04T22:43:00+01:002021-02-02T23:18:09+01:00Gianlucatag:devel.grys.it,2020-01-04:/making-the-minibookdb-database-public.html<p>The biggest limitation (by design) of <a href="https://gitlab.com/mgian/MiniBookDb">MiniBookDB</a> is that it is designed to be deployed only on private network, so no security features. Being in a private network without being accessible from the outside make difficult to check if you already own a book when you are buying one in …</p><p>The biggest limitation (by design) of <a href="https://gitlab.com/mgian/MiniBookDb">MiniBookDB</a> is that it is designed to be deployed only on private network, so no security features. Being in a private network without being accessible from the outside make difficult to check if you already own a book when you are buying one in a shop.</p>
<p>Add that I no longer work with NodeJs and I am not interested to add some security features to it since they are outside the original goal of the project, this leave the problem open.</p>
<p>So enter <strong>Python and Flask</strong>.<br>
The idea is to have a Flask microservice deployed to a public server (a Linode in this case but it is not really important) that is called from MiniBookDB every time a book is added to generate a set of static html pages. </p>
<p>The MiniBookDB call just pass some basic information about the book (title and author) to the API exposed from the microservice that store the book in a local SQLite db and then generate the HTML pages.</p>
<p>The code is really simple, most of it can be found in a lot of tutorial online on how to build a microservice with Python and Flask.</p>
<p>There are 2 class defined <code>DbConn</code> which handles the SQLite connection and operation and <code>HtmlOutput</code> which generate the HTML files. These two classes are necessary only to have some structured code and because the code can be executed as a CLI command.</p>
<p>The code is quite simple, a Flask app is instantiated and then a <code>HTTPBasicAuth</code> instance is created</p>
<div class="highlight"><pre><span></span><code> <span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
<span class="n">auth</span> <span class="o">=</span> <span class="n">HTTPBasicAuth</span><span class="p">()</span>
</code></pre></div>
<p>then a set of routes are defined:</p>
<div class="highlight"><pre><span></span><code><span class="nd">@auth</span><span class="o">.</span><span class="n">get_password</span>
<span class="k">def</span> <span class="nf">get_password</span><span class="p">(</span><span class="n">uname</span><span class="p">):</span>
<span class="o">...</span>
<span class="nd">@auth</span><span class="o">.</span><span class="n">error_handler</span>
<span class="k">def</span> <span class="nf">unauthorized</span><span class="p">():</span>
<span class="k">return</span> <span class="n">make_response</span><span class="p">(</span><span class="n">jsonify</span><span class="p">({</span><span class="s1">'error'</span><span class="p">:</span> <span class="s1">'Want some tea ?'</span><span class="p">}),</span> <span class="mi">418</span><span class="p">)</span>
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/book/store'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">'POST'</span><span class="p">])</span>
<span class="nd">@auth</span><span class="o">.</span><span class="n">login_required</span>
<span class="k">def</span> <span class="nf">add_book</span><span class="p">():</span>
<span class="o">...</span>
</code></pre></div>
<p>The called API is defined by the <code>/book/store</code> POST route that call the <code>add_book</code> method that, as the code show, need authentication to be executed.<br>
The authentication is performed from the <code>@auth</code> routes, one to check the login/password and one to return an error if the credential are not verified. Note the error code returned ;-)</p>
<p>The <code>add_book</code> method then extract the data from the POST call, store them in a JSON object and call an helper function that instantiate the <code>HtmlOutput</code> class to generate the HTML files.</p>
<p>The helper function is necessary since the script can be also used as a command from the CLI if called with the <code>--clirun</code> paramater, which basically regenerate all the HTML files without storing any new record.</p>
<p>The entry point is pretty trivial</p>
<div class="highlight"><pre><span></span><code><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s1">'--clirun'</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s1">'store_true'</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s1">'Generate the html files from cli'</span><span class="p">)</span>
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">clirun</span><span class="p">:</span>
<span class="n">generateHtml</span><span class="p">({})</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">debug</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</code></pre></div>
<p>it just parse the command line arguments and decide if it must run as service or as CLI command.</p>Deploy Pelican blog with git on Linode2019-12-28T22:04:00+01:002019-12-28T23:53:22+01:00Gianlucatag:devel.grys.it,2019-12-28:/deploy-pelican-blog-with-git-on-linode.html<p>Ok, now I have a new blog with Pelican on my pc, but how I can deploy it to my remote server on Linode ?</p>
<p>Aside from the two ways already usable from the Makefile you have by default (ssh and rsync), it is possible to deploy also with Git.</p>
<h3>Disclaimer …</h3><p>Ok, now I have a new blog with Pelican on my pc, but how I can deploy it to my remote server on Linode ?</p>
<p>Aside from the two ways already usable from the Makefile you have by default (ssh and rsync), it is possible to deploy also with Git.</p>
<h3>Disclaimer</h3>
<p>This mini-tutorial is not all mine, I got the informations from various sites and pages, and adapted it to my need. You can find a lot of similar solutions on the Web, many way older than mine. Additionally, I got inspired from the deployment of Hexo.io, another blog generator written in nodejs that I used some time ago, done with a git's hook.</p>
<h3>Prerequisites</h3>
<p>All you need is a working local Pelican blog, to install it you can follow the <a href="https://docs.getpelican.com/en/stable/index.html">Pelican Documentation</a> which explain really well how to do it.</p>
<p>Another thing you need to have is a working Linode's linode with shell access and a working git installation. It is not really important how big.</p>
<h3>Step 1</h3>
<p>Access your server and create a git repository for your blog</p>
<div class="highlight"><pre><span></span><code>mkdir -p /path/to/your/repo
cd /path/to/your/repo
git init --bare
</code></pre></div>
<p>This create a bare Git repository that will not host any files but only the version control (see the git documentation for more info)</p>
<h3>Step 2</h3>
<p>In your repository create a hook caller <code>post-receive</code> in the hooks directory of your repository</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/bash -l</span>
<span class="nv">PATH</span><span class="o">=[</span>your_user_path<span class="o">]</span>
<span class="nv">GIT_REPO</span><span class="o">=</span>/path/to/your/repo
<span class="nv">TMP_GIT_CLONE</span><span class="o">=</span>/tmp/git/your_repo_name
<span class="nv">PUBLIC_WWW</span><span class="o">=</span>/path/to/your/web_root
git clone <span class="nv">$GIT_REPO</span> <span class="nv">$TMP_GIT_CLONE</span>
cp -a TMP_GIT_CLONE/* PUBLIC_WWW
rm -Rf <span class="nv">$TMP_GIT_CLONE</span>
<span class="nb">exit</span>
</code></pre></div>
<h3>Step 3</h3>
<p>In your local Pelican directory, clone your git repository of your blog, with the usual git command <code>git clone [your_user]@your_serve:/path/to/your/repo output</code></p>
<p>The output at the end is important since it is the directory where Pelican generate your site.</p>
<p>At this point your are ready to deploy your site. You simply need to generate it using one of this ways:
* <code>pelican -lr</code>
* <code>make html</code></p>
<p>I use the first option since it start a local server <code>http://localhost:8000</code> which allow you to see your blog locally with a browser, but also the latest can be used.</p>
<p>Once you have generated the html files for your articles, pages and everything else, you just need to add, commit and push your repo t deploy your site</p>
<div class="highlight"><pre><span></span><code>git add .
git commit -am "First article"
git push
</code></pre></div>
<p>at this point you should see something like this:</p>
<div class="highlight"><pre><span></span><code><span class="n">Enumerating</span><span class="w"> </span><span class="n">objects</span><span class="o">:</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span><span class="w"> </span><span class="n">done</span><span class="p">.</span><span class="w"></span>
<span class="n">Counting</span><span class="w"> </span><span class="n">objects</span><span class="o">:</span><span class="w"> </span><span class="mi">100</span><span class="o">%</span><span class="w"> </span><span class="p">(</span><span class="mi">5</span><span class="o">/</span><span class="mi">5</span><span class="p">),</span><span class="w"> </span><span class="n">done</span><span class="p">.</span><span class="w"></span>
<span class="n">Delta</span><span class="w"> </span><span class="n">compression</span><span class="w"> </span><span class="n">using</span><span class="w"> </span><span class="n">up</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="mi">8</span><span class="w"> </span><span class="n">threads</span><span class="w"></span>
<span class="n">Compressing</span><span class="w"> </span><span class="n">objects</span><span class="o">:</span><span class="w"> </span><span class="mi">100</span><span class="o">%</span><span class="w"> </span><span class="p">(</span><span class="mi">3</span><span class="o">/</span><span class="mi">3</span><span class="p">),</span><span class="w"> </span><span class="n">done</span><span class="p">.</span><span class="w"></span>
<span class="n">Writing</span><span class="w"> </span><span class="n">objects</span><span class="o">:</span><span class="w"> </span><span class="mi">100</span><span class="o">%</span><span class="w"> </span><span class="p">(</span><span class="mi">3</span><span class="o">/</span><span class="mi">3</span><span class="p">),</span><span class="w"> </span><span class="mi">338</span><span class="w"> </span><span class="n">bytes</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="mf">338.00</span><span class="w"> </span><span class="n">KiB</span><span class="o">/</span><span class="n">s</span><span class="p">,</span><span class="w"> </span><span class="n">done</span><span class="p">.</span><span class="w"></span>
<span class="n">Total</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="p">(</span><span class="n">delta</span><span class="w"> </span><span class="mi">2</span><span class="p">),</span><span class="w"> </span><span class="n">reused</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">(</span><span class="n">delta</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"></span>
<span class="n">remote</span><span class="o">:</span><span class="w"> </span><span class="n">Cloning</span><span class="w"> </span><span class="n">into</span><span class="w"> </span><span class="s">'/tmp/git/devel.grys.it'</span><span class="p">...</span><span class="w"></span>
<span class="n">remote</span><span class="o">:</span><span class="w"> </span><span class="n">done</span><span class="p">.</span><span class="w"></span>
<span class="n">To</span><span class="w"> </span><span class="n">git</span><span class="p">.</span><span class="n">grys</span><span class="p">.</span><span class="n">it</span><span class="o">:/</span><span class="n">home</span><span class="o">/</span><span class="n">git</span><span class="o">/</span><span class="n">devel</span><span class="p">.</span><span class="n">grys</span><span class="p">.</span><span class="n">it</span><span class="w"></span>
<span class="w"> </span><span class="n">e6f9934</span><span class="p">..</span><span class="n">ec16614</span><span class="w"> </span><span class="n">master</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">master</span><span class="w"></span>
</code></pre></div>
<p>which is the message I got for this site.
If you get an error, it will be displayed in the message to allow you to solve the problem (permission problem, missing directory, wrong path, whatever)</p>
<p>If no error is reported, congratulation, you just deployed your blog on your server, just open a browser and navigate to it to do a final check.</p>Welcome2019-12-27T21:17:00+01:002019-12-27T22:15:25+01:00Gianlucatag:devel.grys.it,2019-12-27:/welcome.html<p>Welcome to this site.</p>
<p>Hope it will get some contents soon ;-)</p>