When a Pipe isn't enough: TTYs in Java

May 29, 2021

I needed to launch Docker containers in Java and pipe the result pack to some other place. This included interacting with that container directly via standard in/out. Nothing easier than that, you can do this with docker like this:

docker run -it ubuntu:20.04

Ok, then lets launch it via Java:

var processCreation = new ProcessBuilder("docker", "run", "-it", "ubuntu:20.04");
processCreation.redirectErrorStream();
processCreation.redirectOutput();
processCreation.redirectInput();
var process = processCreation.start();
redirectToRightPlace(process.getInputStream());
redirectToRightPlace(process.getErrorStream());
redirectToRightPlace(process.getOutputStream());

int exitCode = process.waitFor();

Unfortunately, you get this error back from the process:

the input device is not a TTY

Event when you ignore this error, interactive apps like a shell, text editors etc won’t work properly. So, what is this TTY anyway?

File Isn’t a TTY
Figure 1. File Is Not a TTY
Continue reading →

On Linux (Unix?) You Can Make Up a User ID On The Fly

May 4, 2021

Recently I’ve been working with Docker, launching non-root containers. Mostly because I mounted files into the container I didn’t want every file to be owned by root. I use commands like this: docker run --user="$(id --user):$(id --group) -v $PWD:/mounted-directory <image> <comand>. This way the processes inside the container use the same user id as the current user, so any file created inside the container on the mounted directory can easily be read and changed.

What happens if you pick a random user id, one which doesn’t exist? Try it:

docker run --detach --rm --user=42421:42421 busybox sleep 10
> 542d4de888751e6d067ddd84bf3b9f21698e2af4a0a90844b586c92a3d47d6d
ps aux | grep sleep
> 42421      88497  0.0  0.0   1308     4 ?        Ss   14:28   0:00 sleep 10
> roman      88539  0.0  0.0   6404  2292 pts/11   S+   14:28   0:00 grep --color=auto sleep
Continue reading →

Make a Test Fail First

April 18, 2021

When I write tests and I exactly know what I need I write a test first. Other times I experiment with the implementation and then write some tests after the code exists. And for some code the effort to write a automated tests is not worth it.

However, there is one advice I need to remind myself from time to time: Write a failing test first. Or, when you write the test afterward, make the test fail by screwing the implementation. Why? Let’s look at small test example:

Continue reading →

Adding an Extra Indirection to Enable Code Reloading in Clojure/Java Interop Code

February 14, 2021

One of the killer features of Clojure is its ability to reload code and incrementally develop in a running environment. Another strength of Clojure/Clojure script is that it is deliberately a hosted language, leveraging the broader Java/Javascript ecosystem for libraries, frameworks, etc.

However, the dynamic code reloading and interacting with Java libraries can create some friction. Adding another layer of indirection sometimes reduces that friction. Let’s look at an example. Let’s assume we have a large Java library to which you provide a callback functions/object. Like an HTTP-server, network- or some other library. Easy, you implement the interface of the library. Note that the library instance is preserved with defonce.

Java and Clojure Best Friends Forever
Figure 1. Java and Clojure Best Friends Forever
Continue reading →

C# Updates for the Absent C# Developer (C# 6.0 and newer overview)

December 5, 2020

This post is part of C# Advent Calendar 2020.

Update 6. December 2020: Some good small discussion on Reddit.com

It has been a while since I actively developed in C#. I mostly worked with C# and .NET during the 3.0 to 4.5 days and I did async/await work very early on, so I skip over that as well. After a job change, I didn’t touch C# for actual work. I mostly just watched the development from the sidelines via news. Today, I take a short look at some features. I will skip a lot and just add some of my highlights tour.

C# grew up
Figure 1. C# All Grown Up
Continue reading →