/til

Today I learned ...

Primary LanguagePHP

(For usage refer to USAGE.md)

Multi-Project with Gradle

Gradle supports including other projects as dependencies. A good example for this can be found here as explained in the blog post.

The author summarises the three msot important things as:

  • A multi-project build must have the settings.gradle file in the root directory of the root project because it specifies the projects that are included in the multi-project build.
  • If we have to add common configuration or behavior to all projects of our multi-project build, we should add this configuration (use allprojects) to the build.gradle file of our root project.
  • If we have to add common configuration or behavior to the subprojects of our root project, we should add this configuration (use subprojects) to the build.gradle file of our root project.

I ended up using this approach for a game I'm developing. The core module is one project and all the frontends are other projects.

Partial Add with Git

Using git add -p you can interactively choose which parts of your work you want to add/stage. This even allows you to add different parts of a file, while leaving out others.

Source: https://www.youtube.com/watch?v=duqBHik7nRo

Copy paste for files in linux

xclip is an awesome tool which can be used to pipe output to the clipboard. Use -selection c so that you can paste using Ctrl + V.

# example
xclip -selection c ~/somefile.txt

forceCoversAnnotation in PHPUnit

Up until now I've always been using the beStrictAboutCovers in the phpunit.xml configuration file. Today I learned about the forceCoversAnnotation annotation.

The effect is similar: only the code specified by @covers will count towards the total code coverage. With forceCoversAnnotation however the @uses annotation is not required. I like @uses but if often clogs up a test class when using lots of small value objects.

Screenkey for Live Coding

screenkey is a python app which shows key presses in an overlay on the screen. Nice for live coding to show off key combinations and shortcuts.

--mods-only shows only modifiers, because normal letters are probably not interesting and --vis-shift shows shift every time it is pressed.

No installation required, just start the app after cloning the repo ./screenkey --mods-only --vis-shift

Free HTTPS from Lets Encrypt

Let's Encrypt provides free certificates for everyone. 90 day renewal can be automated through cronjobs.

Explained by a developer: https://www.youtube.com/watch?v=zJ0JMl1B7yY

Solve difficult merges with git-imerge

git-imerge solves the problem of resolving many merge conflicts in large merge operations.

Video by the developer: http://www.youtube.com/watch?v=FMZ2_-Ny_zc

bcat pipes cli output to the browser

I finally decided to find out how to pipe HTML straight to a browser without having to write it to a file and then open that file in the browser and then deleting the file etc.

The solution is a small ruby gem called bcat and it's usage is just as you'd imagine (taken from the project's website):

# With build tools:

make test |bcat
rake test |bcat

# As a clipboard viewer:

pbpaste  |bcat   # macos
xclip -o |bcat   # X11

# For previewing HTML:

markdown README.md |bcat
redcloth README.textile |bcat
erb -T - template.erb |bcat
mustache < template.mustache |bcat
pygmentize -Ofull,style=colorful -f html main.c |bcat

Additive and multiplicative complexity

B. Meyer makes an interesting point (among many from his book Agile! - The Good, the Hype, and the Ugly) about the different types of complexities in software projects. He compares the two types to pasta:

  • Additive complexity is like lasagne. You just keep piling new parts on top of the existing parts and it works (this is, of course, an ideal for agile projects).
  • Multiplicative complexity, however, is more like linguine (or spaghetti), meaning the parts are entangled and hard to separate. Projects which have lots of this types of complexities (which is more than one might think) require some upfront planning to reduce waste (which would be the result of treating these tasks in pure agile manner).## Native Watch Using inotify-tools

Don't bother installing node or ruby gems when you can simply run the following inline command on any UNIX system with inotify-tools installed:

# watch a single file for any type of changes and display on change
while inotifywait someText.txt; do cat someText.txt; done

# watch a folder for any type of change and run make if there is
while inotifywait -r src; do make; done

Magic Variables in Bash

  • $0 - $99 x-th argument provided to the script/function. $0 is always the script name even when accessed from within a function. $1+ will work in functions.

  • $? Exit code of the last process.

  • $_ Last argument.

  • $! PID of last process.

  • $@ All arguments.

Note: Always quote variables to avoid word-splitting (except when using [[ for tests). Run shellcheck to make sure.

Test for Symlinks in Bash

Use -L instead of -h for compatibility.

if [[ -L /path/to/suspected_symlink ]]; then
  echo "is symlink"
else
  echo "no symlink"
fi  

Bash Arrays

Declare a variable with ARRAY=(one two three) and reference it using echo ${ARRAY[*]} or echo ${ARRAY[2]} for a single element.

Note that brackets are not required in for statements: for i in 1 2 3; do echo $i; done

Generate content for Postman requests

Postman provides dynamic variables which can be used to generate content for requests e.g.

{
    "name": "Test Variant {{$randomInt}}",
    "id": "{{$guid}}"
}

See: https://learning.postman.com/docs/postman/variables-and-environments/variables-list/

KDEWallet

By using kwalletcli you can poll for entries using e.g.

kwallet-query -l kdewallet -f Toolbox -r 'JetBrains Account OAuth'

Use git for-each-ref instead of git branch

git for-each-ref is better suited for automated branch parsing than git branch.

Example usage which deletes branches which aren't on upstream:

git for-each-ref --shell --format='ref=%(refname:short); gone=%(if:equals=[gone])%(upstream:track)%(then)gone%(end); if [ "gone" = "$gone" ]; then echo "upstream for $ref is gone, will delete."; git branch -D "$ref"; else echo "will not delete $ref."; fi' 'refs/heads/**' | while read cmd; do eval "$cmd"; done

Jira - Find Tickets you Commented On

issueFunction in commented("by currentUser()")

Renew an expired PGP key

gpg --list-keys 2>/dev/null | grep <your_email> -C2
gpg --edit-key <the_key_id_you_want>

# interactive prompt starts
key 0 
# note you will not see a * next to the key, but unless there
# is an error the key is selected
expire
1y
key 1
expire
1y
# ... for all keys and subkeys
save

# publish the change
gpg --keyserver pgp.mit.edu --send-keys <the_key_id_you_want>

Shortcut for KDE Window Settings

KDE special window settings can be accessed even without a titlebar by using the shortcut Alt + F3. From there you can set opacity, window size, borders etc.

Show hardware configuration on Unix systems

inxi is a convenient tool to display system information in a readable well formatted way. Use the -F flag to display all information and optionally -c 0 in order to turn off colors (because it looked weird on my terminal).

Example:

inxi -F -c 0
System:    Host: lin-haeuslmannm Kernel: 4.15.0-159-generic x86_64 bits: 64 Desktop: KDE Plasma 5.12.9
           Distro: Ubuntu 18.04.6 LTS
Machine:   Device: laptop System: Dell product: XPS 15 9560 serial: N/A
           Mobo: Dell model: 05FFDN v: A00 serial: N/A UEFI: Dell v: 1.23.1 date: 05/25/2021
Battery    BAT0: charge: 61.4 Wh 100.0% condition: 61.4/97.0 Wh (63%)
           hidpp__0: charge: N/A condition: NA/NA Wh
CPU:       Quad core Intel Core i7-7700HQ (-MT-MCP-) cache: 6144 KB
           clock speeds: max: 3800 MHz 1: 800 MHz 2: 800 MHz 3: 800 MHz 4: 800 MHz 5: 800 MHz 6: 800 MHz
           7: 800 MHz 8: 800 MHz
Graphics:  Card-1: Intel Device 591b
           Card-2: NVIDIA GP107M [GeForce GTX 1050 Mobile]
           Display Server: x11 (X.Org 1.19.6 ) driver: i915
           Resolution: 1920x1080@60.01hz, 1920x1080@60.00hz, 1920x1080@60.00hz
           OpenGL: renderer: Mesa DRI Intel HD Graphics 630 (KBL GT2) version: 4.6 Mesa 20.0.8
Audio:     Card-1 Intel CM238 HD Audio Controller driver: snd_hda_intel Sound: ALSA v: k4.15.0-159-generic
           Card-2 Asahi Kasei Microsystems AK5370 I/F A/D Converter driver: USB Audio
           Card-3 Logitech OrbiCam driver: USB Audio
           Card-4 Realtek driver: USB Audio
Network:   Card-1: Qualcomm Atheros QCA6174 802.11ac Wireless Network Adapter driver: ath10k_pci
           IF: wlp2s0 state: up mac: 9c:b6:d0:e9:ca:77
           Card-2: Atheros
           IF: null-if-id state: N/A speed: N/A duplex: N/A mac: N/A
Drives:    HDD Total Size: 1024.2GB (45.5% used)
           ID-1: /dev/nvme0n1 model: PC300_NVMe_SK_hynix_1TB size: 1024.2GB
Partition: ID-1: / size: 407G used: 378G (98%) fs: ext4 dev: /dev/nvme0n1p8
           ID-2: swap-1 size: 64.00GB used: 0.00GB (0%) fs: swap dev: /dev/nvme0n1p7
RAID:      No RAID devices: /proc/mdstat, md_mod kernel module present
Sensors:   System Temperatures: cpu: 65.5C mobo: N/A
           Fan Speeds (in rpm): cpu: 3678 fan-2: 3713
Info:      Processes: 484 Uptime: 1:53 Memory: 13523.0/32017.9MB Client: Shell (zsh) inxi: 2.3.56

Filter JSON array using jq

If you are trying to find a specific element within a JSON array you can use jq's select() filter.

Example:

jq '.services[] | select(.name == "awesome-service") | .version' services.json

Select the key of a map of objects using jq

Given an object like:

{
    "key1": {
        "key": "value1"
    },
    "key2": {
      "key": "value2"
    }
}

you can use a combination of map_values, select and contains to find the right object and then keys to get the matching keys:

map_values(select(contains({"key": "value2"}))) | keys[]
  • contains(element): returns true if whatever is passed into it matches
  • select(boolean_expression): returns the input or nothing if the expression doesn't match
  • map_values(x): runs the filter function x on all inputs

the same function can also be written using the update-assignment operator |=:

.[] |= select(contains({"key": "value2"})) | keys[]

.[] creates an iterator and |= assigns a new value to each element. Similarly to the previous function empty values are filtered out using the combination of select and contains.

Fetch all available gists from logged in account

You can use the GitHub API in order to download a list of all public and private gists from a logged in account (i.e. Bearer token):

curl -L \                                                                                                        ─╯
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer $(secret-tool lookup keyId GitHubPersonalAccessToken)" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/gists

Generated on mar 19 dic 2023 13:50:10 CET