golang-github-gorilla-css for Fedrico.
RuboCop::Packaging to v0.5.RuboCop::Packaging to v0.5.RuboCop::Packaging.faraday and faraday_middleware.RuboCop::Packaging to v0.5.RuboCop::Packaging amongst other used extensions.:wq for today.
if (srcImage.format() != QImage::Format_ARGB32)
srcImage = srcImage.convertToFormat(QImage::Format_ARGB32);
// ...
if (!WebPPictureImportBGRA(&picture, srcImage.bits(), srcImage.bytesPerLine()))
// ...
QImage::Format_ARGB32 format, and
then passing the bytes into WebP s import function. With this format, the image
is stored using a 32-bit ARGB format (0xAARRGGBB). This means that the bytes
will be 0xBB, 0xGG, 0xRR, 0xAA or little endian and 0xAA, 0xRR, 0xGG, 0xBB on
big endian. However, WebPPictureImportBGRA expects the first format on all
architectures.
The fix was to use QImage::Format_RGBA8888. As the QImage documentation
says, with this format the order of the colors is the same on any architecture
if read as bytes 0xRR, 0xGG, 0xBB, 0xAA.
Issue 2: qimage_converter_map structure (code review)
The code seems to already support big endian. But maybe you can spot the error?
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
0,
convert_ARGB_to_ARGB_PM,
#else
0,
0
#endif
struct Data
quint32 m_index : IndexBits;
quint32 m_counter : CounterBits;
quint32 m_unused : 2;
;
union
Data d;
quint32 m_handle;
;
QHandle(quint32 i, quint32 count)
d.m_index = i;
d.m_counter = count;
d.m_unused = 0;
m_handle will be different depending on endianness!
So the test that was expecting a particular value with given constructor
arguments was failing. I fixed it by using the following macro:
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
#define GET_EXPECTED_HANDLE(qHandle) ((qHandle.index() << (qHandle.CounterBits + 2)) + (qHandle.counter() << 2))
#else /* Q_LITTLE_ENDIAN */
#define GET_EXPECTED_HANDLE(qHandle) (qHandle.index() + (qHandle.counter() << qHandle.IndexBits))
#endif
reinterpret_cast, such as:
quint32 *objectTable = reinterpret_cast<quint32*>(data + qmlUnit->offsetToObjects);
QModbusPdu::FunctionCode code = QModbusPdu::Invalid;
if (stream.readRawData((char *) (&code), sizeof(quint8)) != sizeof(quint8))
return stream;
QModbusPdu::FunctionCode is an enum, so code is a multi-byte value (even if
only one byte is significant). However, (char *) (&code) returns a pointer to
the first byte of it. It is the needed byte on little endian systems, but it is
the wrong byte on big endian ones!
The correct fix was using a temporary one-byte variable:
quint8 codeByte = 0;
if (stream.readRawData((char *) (&codeByte), sizeof(quint8)) != sizeof(quint8))
return stream;
QModbusPdu::FunctionCode code = (QModbusPdu::FunctionCode) codeByte;
qt_is_ascii (code review)
This function, as the name says, checks whether a string is ASCII. It does
that by splitting the string into 4-byte chunks:
while (ptr + 4 <= end)
quint32 data = qFromUnaligned<quint32>(ptr);
if (data &= 0x80808080U)
uint idx = qCountTrailingZeroBits(data);
ptr += idx / 8;
return false;
ptr += 4;
idx / 8 is the number of trailing zero bytes. However, the bytes which are
trailing on little endian are actually leading on big endian! So we can use
qCountLeadingZeroBits there.
Issue 7: the bundled copy of tinycbor (upstream pull request)
Similar to issue 5, the code was reading into the wrong byte:
if (bytesNeeded <= 2)
read_bytes_unchecked(it, &it->extra, 1, bytesNeeded);
if (bytesNeeded == 2)
it->extra = cbor_ntohs(it->extra);
extra has type uint16_t, so it has two bytes. When we need only one byte,
we read into the wrong byte, so the resulting number is 256 times higher on
big endian than it should be. Adding a temporary one-byte variable fixed it.
Issue 8: perfparser, part of Qt Creator (code review)
Here it is not trivial to find the issue just looking at the code:
qint32 dataStreamVersion = qToLittleEndian(QDataStream::Qt_DefaultCompiledVersion);
undefined reference to QDataStream::Version qbswap(QDataStream::Version)'On little endian systems,
qToLittleEndian is a no-op, but on big endian
systems, it is a template function defined for some known types. But it turns
out we need to explicitly convert enum values to a simple type, so the fix
was passing qint32(QDataStream::Qt_DefaultCompiledVersion) to that function.
Issue 9: Qt Personal Information Management (code review)
The code in test was trying to represent a number as a sequence of bytes,
using reinterpret_cast:
static inline QContactId makeId(const QString &managerName, uint id)
return QContactId(QStringLiteral("qtcontacts:basic%1:").arg(managerName), QByteArray(reinterpret_cast<const char *>(&id), sizeof(uint)));
id = qToLittleEndian(id);
Reviving Very Old X Code
I've taken the week between Christmas and New Year's off this year. I
didn't really have anything serious planned, just taking a break from
the usual routine. As often happens, I got sucked into doing a project
when I received this simple bug report
Debian Bug #974011
I have been researching old terminal and X games recently, and realized
that much of the code from 'xmille' originated from the terminal game
'mille', which is part of bsdgames.
...
[The copyright and license information] has been stripped out of all
code in the xmille distribution. Also, none of the included materials
give credit to the original author, Ken Arnold.
The reason the 'xmille' source is missing copyright and license
information from the 'mille' files is that they were copied in
before that information was added upstream. Xmille forked from Mille
around 1987 or so. I wrote the UI parts for the system I had at the
time, which was running X10R4. A very basic port to X11 was done at
some point, and that's what Debian has in the archive today.
At some point in the 90s, I ported Xmille to the
Athena widget set,
including several custom widgets in an Xaw extension library,
Xkw. It's a lot better than the version in Debian, including displaying the
cards correctly (the Debian version has some pretty bad color issues).
Here's what the current Debian version looks like:
Fixing The Bug
To fix the missing copyright and license information, I imported the
mille source code into the "latest" Xaw-based version. The updated
mille code had a number of bug fixes and improvements, along with the
copyright information.
That should have been sufficient to resolve the issue and I could have
constructed a suitable source package from whatever bits were needed
and and uploaded that as a replacement 'xmille' package.
However, at some later point, I had actually merged xmille into a
larger package, 'kgames', which also included a number of other
games, including Reversi, Dominoes, Cribbage and ten Solitaire/Patience
variants. (as an aside, those last ten games formed the basis for my
Patience Palm Pilot application, which seems to have inspired an
Android App of the same name...)
So began my
yak shaving holiday.
Building Kgames in 2020
Ok, so getting this old source code running should be easy, right?
It's just a bunch of C code designed in the 80s and 90s to work on
VAXen and their kin. How hard could it be?
And here's my favorite solitaire variant too:
But They Look So Old
Yeah, Xaw applications have a rustic appearance which may appeal to
some, but for people with higher resolution monitors and well
seasoned eyesight, squinting at the tiny images and text makes it
difficult to enjoy these games today.
How hard could it be to update them to use larger cards and scalable
fonts?
Xkw version 2.0
I decided to dig in and start hacking the code, starting by adding new
widgets to the Xkw library that used cairo for drawing instead of core
X calls. Fortunately, the needs of the games were pretty limited, so I
only needed to implement a handful of widgets:
And here's spider:
Once kgames 1.0 reaches Debian unstable, I'll upload these new
versions.
Formal sector issues
Just today it was published that output from eight formal sectors of the economy who make the bulk of the Indian economy were down on a month to month basis . This means all those apologists for the Government who said that it was ok that the Govt. didn t give the 20 lakh crore package which was announced. In fact, a businessman from my own city, a certain Prafull Sarda had asked via RTI what happened to the 20 lakh crore package which was announced? The answers were in all media as well as newspapers but on the inside pages. You can see one of the article sharing the details here. No wonder Vivek Kaul also shared his take on the way things will hopefully go for the next quarter which seems to be a tad optimistic from where we are atm.
Eight Sectors declining in Indian Economy month-on-month CNBC TV 18
On doing 540 no-source-change source-only uploads in two weeks
So I've been doing 540 no-source-change source-only uploads in the last two weeks
and am planning to do 3000 more in January 2021. We'll see how that goes
Let me explain what I have been doing and why.
So, starting
with the Bullseye release cycle the Release Team changed policy: only packages which were
build on buildds are allowed to migrate to testing.
Which is pretty nice for reproducible builds
as this also ensures that a .buildinfo file is available for anyone wanting to reproduce the
binaries of that package.
However, there are many binary (and source) packages in Debian which were
uploaded before 2016 (which is when .buildinfo files were introduced) or
were uploaded with binaries until that change in release policy July 2019.
Then Ivo De Decker scheduled binNMUs for all the affected packages but due
to the way binNMUs work, he couldn't do anything about arch:all packages
as they currently cannot be rebuilt with binNMUs.
Ivo and myself discussed what could be done about the remaining packages
and (besides long complicated changes to Debian's workflows) the only thing
deemed possible was doing many many source uploads with just a new changelog
entry:
* Non maintainer upload by the Reproducible Builds team. * No source change upload to rebuild on buildd with .buildinfo files.These packages are all inherently buggy, because Debian policy mandates that packages should be reproducible and without .buildinfo files one cannot reproducibly rebuild packages. So instead of filing many many bugs we've decided to just fix these bugs by doing a no-source-change source uploads. One nice aspect of these uploads is that there's no follow-up work imposed on the maintainer: whether they keep that changelog entry or whether they discard it, it does not matter. So Ivo had developed an SQL query which showed 570 packages needing an update roughly two weeks ago, on December 18 and so I started slowly. This is the amount of NMUs I did in the last days:
for i in $(seq 18 30) ; do echo -n "Dec $i: " ; ls -lart1 done/*upload grep -c "Dec $i" ; done Dec 18: 12 Dec 19: 0 Dec 20: 3 Dec 21: 13 Dec 22: 13 Dec 23: 16 Dec 24: 4 Dec 25: 28 Dec 26: 0 Dec 27: 38 Dec 28: 198 Dec 29: 206 Dec 30: 9About ten packages had FTBFS bugs preventing an upload and seven packages were uploaded by the maintainer before me. I've seen two cases of sudden maintainer uploads after 8 and 10 years of no activity! So what did I do for each upload?
| Publisher: | Little, Brown and Company |
| Copyright: | October 2020 |
| ISBN: | 0-316-46134-2 |
| Format: | Kindle |
| Pages: | 315 |
backupsvr: id: .... exchpub: ... signpub: ... noisepub: ... via: ["spooler"]This tells NNCP that data destined for backupsvr should always be sent via spooler first. You can then arrange for the nncp-daemon to run on the spooler, and nncp-caller or nncp-call on the backupsvr. Or, alternatively, airgapped between the two with nncp-xfer. Generating Backup Data Now, on the laptop, install simplesnap (2.0.0 or above). Although you won t be backing up to the local system, simplesnap still maintains a hostlock in ZFS. Prepate a dataset for it:
zfs create tank/simplesnap zfs set org.complete.simplesnap:exclude=on tank/simplesnapThen, create a script /usr/local/bin/runsimplesnap like this:
#!/bin/bash set -e simplesnap --store tank/simplesnap --setname backups --local --host hostname \ --receivecmd /usr/local/bin/simplesnap-queue \ --noreap su nncp -c '/usr/local/nncp/bin/nncp-toss -noprogress -quiet' if ip addr grep -q 192.168.65.64; then su nncp -c '/usr/local/nncp/bin/nncp-call -noprogress -quiet -onlinedeadline 1 spooler' fiThe call to simplesnap sets it up to send the data to simplesnap-queue, which we ll create in a moment. The receivmd, plus noreap, sets it up to run without ZFS on the local system. The call to nncp-toss will process any previously-received inbound NNCP packets, if there are any. Then, in this example, we do a very basic check to see if we re on the LAN (checking 192.168.65.64), and if so, will establish a connection to the spooler to transmit the data. If course, you could also do this over the Internet, with tor, or whatever, but in my case, I don t want to automatically do this in case I m tethered to mobile. I figure if I want to send backups in that case, I can fire up nncp-call myself. You can also use nncp-caller to set up automated connections on other schedules; there are a lot of options. Now, here s what /usr/local/bin/simplesnap-queue looks like:
#!/bin/bash set -e set -o pipefail DEST=" echo $1 sed 's,^tank/simplesnap/,,' " echo "Processing $DEST" >&2 # stdin piped to this su nncp -c "/usr/local/nncp/bin/nncp-exec -nice B -noprogress backupsvr zfsreceive '$DEST'" >&2 echo "Queued for $DEST" >&2This is a pretty simple script. simplesnap will call it with a path based on the store, with the hostname after; so, for instance, tank/simplesnap/laptop/root or some such. This script strips off the leading tank/simplesnap (which is a local fragment), leaving the host and dataset paths. Then it just pipes it to nncp-exec. -nice B classifies it as low-priority bulk data (so if you have some more important interactive data, it would be sent first), then passes it to whatever the backupsvr defines as zfsreceive. Receiving ZFS backups In the NNCP configuration on the recipient s side, in the laptop section, we define what command it s allowed to run as zfsreceive:
exec:
zfsreceive: ["/usr/bin/sudo", "-H", "/usr/local/bin/nncp-zfs-receive"]
We authorize the nncp user to run this under sudo in /etc/sudoers.d/local nncp:
Defaults env_keep += "NNCP_SENDER" nncp ALL=(root) NOPASSWD: /usr/local/bin/nncp-zfs-receiveThe NNCP_SENDER is the public key ID of the sending node when nncp-toss processes the incoming data. We can use that for sanity checking later. Now, here s a basic nncp-zfs-receive script:
#!/bin/bash set -e set -o pipefail STORE=backups/simplesnap DEST="$1" # now process stdin runcommand zfs receive -o readonly=on -x mountpoint "$STORE/$DEST"And there you have it all the basics are in place. Update 2020-12-30: An earlier version of this article had zfs receive -F instead of zfs receive -o readonly=on -x mountpoint . These changed arguments are more robust.
#!/bin/bash
set -e
set -o pipefail
STORE=backups/simplesnap
# $1 will be the host/dataset
DEST="$1"
HOST=" echo "$1" sed 's,/.*,,g' "
if [ -z "$HOST" ]; then
echo "Malformed command line"
exit 5
fi
# Log a message
logit ()
logger -p info -t " basename "$0" [$$]" "$1"
# Log an error message
logerror ()
logger -p err -t " basename "$0" [$$]" "$1"
# Log stdin with the given code. Used normally to log stderr.
logstdin ()
logger -p info -t " basename "$0" [$$/$1]"
# Run command, logging stderr and exit code
runcommand ()
logit "Running $*"
if "$@" 2> >(logstdin "$1") ; then
logit "$1 exited successfully"
return 0
else
RETVAL="$?"
logerror "$1 exited with error $RETVAL"
return "$RETVAL"
fi
exiterror ()
logerror "$1"
echo "$1" 1>&2
exit 10
# Sanity check
if [ "$HOST" = "laptop" ]; then
if [ "$NNCP_SENDER" != "12345678" ]; then
exiterror "Host $HOST doesn't match sender $NNCP_SENDER"
fi
else
exiterror "Unknown host $HOST"
fi
runcommand zfs receive -F "$STORE/$DEST"
Now you ll capture the ZFS receive output in syslog in a friendly way, so you can look back later why things failed if they did.
Further notes on NNCP
nncp-toss will examine the exit code from an invocation. If it is nonzero, it will keep the command (and associated stdin) in the queue and retry it on the next invocation. NNCP does not guarantee order of execution, so it is possible in some cases that ZFS streams may be received in the wrong order. That is fine here; zfs receive will exit with an error, and nncp-toss will just run it again after the dependent snapshots have been received. For non-ZFS backups, a simple sequence number can handle this issue.
| Publisher: | Tor |
| Copyright: | March 2020 |
| ISBN: | 1-250-21732-6 |
| Format: | Kindle |
| Pages: | 398 |
I am no longer maintaining github-backup.
I'll contine hosting its website and git repo for the time being, but it needs
a new maintainer if it's going to survive.
I don't really think it needs to survive. If the farce of youtube-dl being
removed from github, thus losing access to all its issues and pull
requests, taught us anything, it's that having that happen does not make
many people reconsider their dependence on github. (Not even youtube-dl it
turns out, which is back on there.) Clearly people don't generally
have any interest in backing that stuff up.
As far as the git repositories on Github, they are getting archived very
effectively by softwareheritage.org
which vaccumes up all git repositories from Github. Which points to a
problem, because the same can't be said for git repositories not hosted on
Github. There's a
form to submit them
but the submissions often get hung up needing manual review, and it doesn't
seem to pull in new commits actively if at all, based on the few git
repositories I've had archived there so far.
That seems like something it might be worth building some software to manage.
But it's also just another case of Github's mass bending reality around it;
the average Github user doesn't care about this and still gets archived;
the average self-hosting git user may care about this slightly more, but most
won't get archived, even if that software did get built.
Farmer on-going protests
Before I start with the education system in India which I have talked about many times in the past, first let me share couple of pieces about the farmer movement which is still at Sanghu Delhi border.
<Manjeet Kaur,62 at farmer protest with her friends.
Saket Gokhale s RTI query on digging up NH44
NHAI response to Saket Gokhale s query.
phosh is graphical shell for mobile, touch based devices like
smart phones. It's the default graphical shell on Purism's
Librem 5 (and that's where
it came to life) but projects like postmarketOS,
Mobian and
Debian have picked it up
putting it into use on other devices as well and contributing patches.
This post is meant as a short overview how things are tied together so
further posts can provide more details.
A PHone SHell
As mobile shell phosh provides the interface components commonly
found on mobile devices to
org.gnome.Screensaver or org.gnome.keyring.SystemPrompter and
retrieves user configuration like keybindings via
GSettings from preexisting
schema.
The components of a running graphical session roughly look like this:
The blue boxes are the very same found on GNOME desktop sessions
while the white ones are currently only found on
phones.
feedbackd is explained
quickly: It's used for providing haptic or visual user feedback and
makes your phone rumble and blink when applications (or the shell)
want to notify the user about certain events like incoming phone calls
or new messages. What about phoc and squeekboard?
phoc and squeekboard
Although some stacks combine the graphical shell with the display server
(the component responsible for drawing applications and handling user
input) this isn't the case for phosh. phosh relies on a
Wayland
compositor to be present for that. Keeping shell and compositor apart
has some advantages like being able to restart the shell without
affecting other applications but also adds the need for some
additional communication between compositor and shell. This additional
communication is implemented via Wayland protocols. The Wayland
compositor used with phosh is called
phoc for PHone
Compositor.
One of these additional protocols is wlr-layer-shell.
It allows the shell to reserve space on the screen that is not used
by other applications and allows it to draw things like the top and
bottom bar or lock screen. Other protocols used by phosh (and hence implemented by phoc) are
wlr-output-management
to get information on and control properties of monitors or
wlr-foreign-toplevel-management
to get information about other windows on the display. The later
is used to allow to switch between running applications.
However these (and other) Wayland protocols are not implemented in
phoc from scratch. phoc leverages the
wlroots library for that. The library
also handles many other compositor parts like interacting with the
video and input hardware.
The details on how phoc actually puts things up on the screen deserves
a separate post. For the moment it's sufficient to note that phosh
requires a Wayland compositor like phoc.
We've not talked about entering text without a physical keyboard yet -
phosh itself does not handle that either.
squeekboard is the on
screen keyboard for text (and emoji) input. It again uses Wayland
protocols to talk to the Wayland compositor and it's (like phosh) a
component that wants exclusive access to some areas of the screen
(where the keyboard is drawn) and hence leverages the layer-shell
protocol. Very roughly speaking it turns touch input in that area into
text and sends that back to the compositor that then passes it back to
the application that currently gets the text input. squeekboard's main
author dcz has some more details
here.
The session
So how does the graphical session in the picture above come into existence?
As this is meant to be close to a regular GNOME session it's done via
gnome-session that is
invoked somewhat like:
phoc -E 'gnome-session --session=phosh'
So the compositor phoc is started up, launches gnome-session which
then looks at phosh.session for the session's components. These are
phosh, squeekboard and gnome-settings-daemon.
These then either connect to already running services via D-Bus
(e.g. NetworkManager, ModemManager, ...) or spawn them via D-Bus
activation when required (e.g. feedbackd).
Calling conventions
So when talking about phosh it's good to keep several things apart:
| Publisher: | Running Press |
| Copyright: | December 2020 |
| ISBN: | 0-7624-7248-0 |
| Format: | Kindle |
| Pages: | 236 |
Quick and dirty way to send around audio via network.
I wondered if there's a remote protocol for audio sending, but
I realized there's a swiss army knife that works reasonably well for p-to-p.
To obtain audio from alsa device I can use ecasound and send
it out through stdout, then pipe using ssh, and play back on
the other end.
Should probably use something like rtmp when there's
multiple end points but this works now...
Raspberry pi sshd is at 14 percent CPU time with 16kHz monaural.
Stereo 44.1k probably pushes it to the limit.
Because we see things so often, we see them less and less. Those who live in thanksgiving daily, however, have a way of opening their eyes and seeing the wonders and beauties of this world as though seeing them for the first time. Joseph WirthlinToday is about dirt. I had to learn about it, again, from my 2-year-old last week. She and I were playing outside something we have more time to do right now. She started to roll around in the grass, and asked me to play in the grass, too. As I got close to the ground, I inhaled the wonderfully sweet and earthy scent of spring soil. I hadn t smelled that in a long time. What an unexpected gift. This photo is of a child, having a fantastic time with dirt and water. The more bits of Kansas he had on him, the more shrieks of laughter I heard. It think most adults keep forgetting the joys of simple things like dirt. I am lucky to have children around to remind me. This week, I also had the opportunity to teach my 2-year-old the joys of making big splashes in mud puddles, so maybe I can also remind them on occasion.
See the world as if for the first time; see it through the eyes of a child, and you will suddenly find that you are free. Deepak ChopraRural Kansas, 2016 (I originally wrote this on March 31, and am sharing it on my blog for the first time today.)
To create a new apps script, click "New project" from the scripts dashboard: this will open a code editor, so now cut and paste this code (change the label name to match the one you want to use, and the header too if you're going to use this for another team):
function tagPythonTeamEmails()
// search for all recent threads (hours is the smallest interval searchable)
var threads = GmailApp.search("newer_than:1h");
// this is the label i want to apply to the messages
var label = GmailApp.getUserLabelByName("Debian_Python_Pkgs"); // <-- EDIT THIS
for (var i = 0; i < threads.length; i++)
// get all messages in a given thread
var messages = threads[i].getMessages();
// for each message in the thread
for (var j = 0; j < messages.length; j++)
var message = messages[j];
// needed to have access to the full email: headers + body
var email = message.getRawContent();
// this is the header i want to check for: if present, add label and archive
if (email.indexOf("X-Distro-Tracker-Team: python") > -1) // <-- EDIT THIS
threads[i].addLabel(label);
threads[i].moveToArchive();
(This code is largely inspired by this StackOverflow answer.)
Given we're going to perform changes to the emails, we need to add extra permissions to the script; first we need to toggle the option "View > Show manifest file" which will show the appsscript.json file. Once done, edit it and update the scope of the script to include:
"oauthScopes": [
...
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/gmail.modify"
],
These new permission will be granted when we deploy the script, which we can actually do right now: from the editor window click on "Publish > Deploy from manifest..." and then "Install add-on"; it will make the app script available to operate on Gmail by opening the usual Google grants authorization popup.
Unlike filters defined on the web UI, apps scripts are not triggered every time a mail is received (there's a pub-sub mechanism, but it doesn't look like it would work for this), so if we want to execute periodically the new script, we need to create a time-driven trigger.
The simplest way is probably from the script editor (but you can also follow this doc): "View > Current project's triggers" and then "Add trigger" from there. For my specific use-case i set:
Be aware of quotas and limitations for Apps scripts; in particular the "Triggers total runtime" set to "90 min / day" is what led me to set the trigger every 510 mins.
Use the scripts dashboard (doc) to monitor the script execution logs, in the "My Executions" section, and specifically the "Duration" column: the script execution time depends exclusively on the number of emails to process at every execution, so fine-tune the trigger time to stay within your quota.
The newer_than search operator doesn't allow a granularity smaller than hours (although that's not even documented), so that means we're going to scan multiple times the same emails.
UPDATE (2020-12-26): I've already had to bump from every 5 to every 10 minutes, as otherwise i'd get Exception: Service invoked too many times for one day: gmail. (remember the quota!)
| Publisher: | Penguin Press |
| Copyright: | 2020 |
| ISBN: | 0-525-52263-8 |
| Format: | Kindle |
| Pages: | 335 |
Files:
<md5> <size> filename
Checksums-Sha256:
<sha256> <size> filename
In the above example, where there is exactly on file name, those fields will by default now be folded into:
Files: <md5> <size> filename
Checksums-Sha256: <sha256> <size> filename
For all other multi-line fields, the plugin still falls back to a list of known fields to fold by default as in previous versions.
Spellchecking improvements
The plugin already supported selective spell checking in v0.0.3, where it often omitted spell checking for fields (in deb822 files) where it did not make sense. The spell check feature has been improved by providing a list of known packaging terms/jargo used by many contributors (so autopkgtests is no longer considered a typo). This applies to all file types (probably also those not handled by the plugin as it is just a dictionary).
Furthermore, the plugin also attempts discover common patterns (e.g. file names or command arguments) and exempt these from spell checking in the debian/changelog. This also includes manpage references such as foo.1 or foo(1) . It is far from perfect and relies on common patterns to exclude spell checking. Nonetheless, it should reduce the number of false positive considerably.
Feedback welcome
Please let me know if you run into bugs or would like a particular feature implemented. You can submit bug reports and feature requests in the issue tracker on github.
// Syntax: https://jenkins.io/doc/book/pipeline/syntax/
// project name as we use it in the folder structure and job name
def TfProject = "myproject-I-dev"
// directory relative to the repo checkout inside the jenkins workspace
def jobDirectory = "terraform/dev/$ TfProject "
// informational string to describe the stage or project
def stageEnvDescription = "DEV"
/* Attention please if you rebuild the Jenkins instance consider the following:
- You've to run this job at least *thrice*. It first has to checkout the
repository, then you've to add permisions for the groovy part, and on
the third run you can gather the list of available terraform folder.
- As a safeguard the first first folder name is always the invalid string
"choose-one". That prevents accidential execution of a random project.
- If you add new terraform folder you've to run the "choose-one" dummy rollout so
the dynamic parameters pick up the new folder. */
/* Here we hardcode the path to the correct job workspace on the jenkins host, and
discover the service folder list. We have to filter it slightly to avoid temporary folders created by Jenkins (like @tmp folders). */
List tffolder = new File("/var/lib/jenkins/jobs/terraform $ TfProject /workspace/$ jobDirectory ").listFiles().findAll it.isDirectory() && it.name ==~ /(?i)[a-z0-9_-]+/ .sort()
/* ensure the "choose-one" dummy entry is always the first in the list, otherwise
initial executions might execute something. By default the first parameter is
used if none is selected */
tffolder.add(0,"choose-one")
pipeline
agent any
/* Show a choice parameter with the service directory list we stored
above in the variable tffolder */
parameters
choice(name: "TFFOLDER", choices: tffolder)
// Configure logrotation and coloring.
options
buildDiscarder(logRotator(daysToKeepStr: "30", numToKeepStr: "100"))
ansiColor("xterm")
// Set some variables for terraform to pick up the right service account.
environment
GOOGLE_CLOUD_KEYFILE_JSON = '/var/lib/jenkins/cicd.json'
GOOGLE_APPLICATION_CREDENTIALS = '/var/lib/jenkins/cicd.json'
stages
stage('TF Plan')
/* Make sure on every stage that we only execute if the
choice parameter is not the dummy one. Ensures we
can run the pipeline smoothly for re-reading the
service directories. */
when expression params.TFFOLDER != "choose-one"
steps
/* Initialize terraform and generate a plan in the selected
service folder. */
dir("$ params.TFFOLDER ")
sh 'terraform init -no-color -upgrade=true'
sh 'terraform plan -no-color -out myplan'
// Read in the repo name we act on for informational output.
script
remoteRepo = sh(returnStdout: true, script: 'git remote get-url origin').trim()
echo "INFO: job *$ JOB_NAME * in *$ params.TFFOLDER * on branch *$ GIT_BRANCH * of repo *$ remoteRepo *"
stage('TF Apply')
/* Run terraform apply only after manual acknowledgement, we have to
make sure that the when condition is actually evaluated before
the input. Default is input before when. */
when
beforeInput true
expression params.TFFOLDER != "choose-one"
input
message "Cowboy would you really like to run **$ JOB_NAME ** in **$ params.TFFOLDER **"
ok "Apply $ JOB_NAME to $ stageEnvDescription "
steps
dir("$ params.TFFOLDER ")
sh 'terraform apply -no-color -input=false myplan'
post
failure
// You can also alert to noisy chat platforms on failures if you like.
echo "job failed"
job-dsl side of the story
Having all those when conditions in the pipeline stages above allows us to
create a dependency between successful Seedjob executions and just let that trigger
the execution of the pipeline jobs. This is important because the Seedjob
execution itself will reset all pipeline jobs, so your dynamic parameters are gone.
By making sure we can re-execute the job, and doing that automatically, we still
have up to date parameterized pipelines, whenever the Seedjob ran successfully.
The job-dsl script looks like this:
import javaposse.jobdsl.dsl.DslScriptLoader;
import javaposse.jobdsl.plugin.JenkinsJobManagement;
import javaposse.jobdsl.plugin.ExecuteDslScripts;
def params = [
// Defaults are repo: mycorp/admin, branch: master, jenkinsFilename: Jenkinsfile
pipelineJobs: [
[name: 'terraform myproject-I-dev', jenkinsFilename: 'terraform/dev/myproject-I-dev/Jenkinsfile', upstream: 'Seedjob'],
[name: 'terraform myproject-I-prod', jenkinsFilename: 'terraform/prod/myproject-I-prod/Jenkinsfile', upstream: 'Seedjob'],
],
]
params.pipelineJobs.each job ->
pipelineJob(job.name)
definition
cpsScm
// assume admin and branch master as a default, look for Jenkinsfile
def repo = job.repo ?: 'mycorp/admin'
def branch = job.branch ?: 'master'
def jenkinsFilename = job.jenkinsFilename ?: 'Jenkinsfile'
scm
git("ssh://git@github.com/$ repo .git", branch)
scriptPath(jenkinsFilename)
properties
pipelineTriggers
triggers
if(job.upstream)
upstream
upstreamProjects("$ job.upstream ")
threshold('SUCCESS')
Disadvantages
There are still a bunch of disadvantages you've to consider
Jenkins Rebuilds are Painful
In general we rebuild our Jenkins instances quite frequently. With the
approach outlined here in place, you've to allow the groovy script execution
after the first Seedjob execution, and then go through at least another
round of run the job, allow permissions, run the job, until it's finally
all up and running.
Copy around Jenkinsfile
Whenever you create a new project you've to copy around Jenkinsfiles for each
and every stage and modify the variables at the top accordingly.
Keep the Seedjob definitions and Jenkinsfile in Sync
You not only have to copy the Jenkinsfile around, but you also have to
keep the variables and names in sync with what you define for the Seedjob.
Sadly the pipeline env-vars are not available outside of the pipeline when
we execute the groovy parts.
Kudos
This setup was crafted with a lot of help by
Michael and
Eric.
Next.