Execute Assembly via Tweet

@plzasm

Selection_044.png

Advertisements

Python: Parsing XML and Retaining the Comments

By default, Python’s built-in ElementTree module strips comments as it reads them. The solution is just obscure enough to be hard to find.

import xml.etree.ElementTree as ET

class _CommentedTreeBuilder(ET.TreeBuilder):
    def comment(self, data):
        self.start('!comment', {})
        self.data(data)
        self.end('!comment')

def parse(filepath):
    ctb = _CommentedTreeBuilder()
    xp = ET.XMLParser(target=ctb)
    tree = ET.parse(filepath, parser=xp)

    root = tree.getroot()
    # ...

When enumerating the parsed nodes, the comments will have a tag-name of “!comment”.

ssl: Promoting Existing Client Socket to SSL in C/C++

You may be in a situation where something else produces the sockets for you (such as an event-loop) or you otherwise need to manage the socket rather then allowing something else to.

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>

int main(int argc, char *argv[])
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (!sockfd) {
        printf("Error creating socket.\n");
        return -1;
    }

    struct sockaddr_in sa;
    memset (&sa, 0, sizeof(sa));

    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = inet_addr("172.217.2.196");
    sa.sin_port = htons (443); 

    socklen_t socklen = sizeof(sa);
    if (connect(sockfd, (struct sockaddr *)&sa, socklen)) {
        printf("Error connecting to server.\n");
        return -1;
    }

    SSL_library_init();
    SSLeay_add_ssl_algorithms();
    SSL_load_error_strings();

    const SSL_METHOD *meth = TLSv1_2_client_method();
    SSL_CTX *ctx = SSL_CTX_new (meth);

    SSL *ssl = SSL_new (ctx);
    if (ssl == NULL) {
        printf("Could not create SSL context.\n");
        return -1;
    }

    SSL_set_fd(ssl, sockfd);

    int err = SSL_connect(ssl);
    if (err <= 0) {
        printf("Could not connect.\n");
        return -1;
    }

    printf ("SSL connection using %s\n", SSL_get_cipher (ssl));

    // Do send/receive here.

    return 0;
}

Adapted from openssl-in-c-socket-connection-https-client, and works with both OpenSSL and BoringSSL.

Use ADB to Connect to Your Android Device From a Docker Container

You may have a use-case where you want to write software to manipulate an Android device using a system or set of tools that are not natively available from your current system. However, you might be able to expose this as a Docker image. For example, your device is (or will be) connected to a Windows machine and you really want to or need to use Linux tools.

No problem. ADB implicitly uses a client-server model: The ADB tool (on your system) connects to the ADB server (runs in the background on your system) which interacts with the ADB daemon (runs on your device). This means that we can forward requests from ADB on the command-line in the guest container in Docker to the ADB server on the host system.

The ADB client and server have to be at the same version, or the client will indiscriminately kill/restart your ADB server. So, as I am currently running Ubuntu 14.04 on my host system, I will do the same in Docker.

First, I will make sure the ADB server is running on my host system. Most of the subcommands that will automatically start the local server, but I will start it directly:

$ adb start-server
* daemon not running. starting it now on port 5037 *
* daemon started successfully *

Now, I will start a container in Docker with Ubuntu 14.04 and automatically install ADB before dropping to a prompt. Note that we are passing “–network=host” in order to share the host’s network identity:

$ docker run -i -t --network=host ubuntu:14.04 /bin/bash -c "sudo apt-get update && sudo apt-get install -y android-tools-adb && /bin/bash"

Eventually, you will end-up at the prompt. Just do something simple like enumerating the devices:

root@mlll2664:/# adb devices
List of devices attached 
05157df572841820 device

The “mlll2664” hostname, represented in the prompt in the Docker container, is, actually, the same hostname as my host system.

So, there you go. Not too painful.

 

Verifying Gerrit CRs to Your Jenkins’ Pipeline’s Shared Libraries

Jenkins’ pipelines represent a totally different direction from traditional, script-based jobs. Instead of specifying your SCM configuration and other build semantics in your job, you mostly script them out via a pipeline (“Jenkinsfile”) file, which is a heterogeneous script/declarative mess. Although you can be purely declarative, this is sometimes too strict to be useful, e.g. not being able to have traditional variable assignments in order to pass information between steps. Even though there are drawbacks, your whole workflow is largely version-controlled.

One of the drawbacks is the complexity of managing shared-library dependencies that you might have in order to make some of your Java/Groovy logic reusable. You can define these in your project (or, the case of multibranch pipelines, the folder) or at the admin level. You can also define these on the fly in the code.

Gerrit change-requests are applied essentially by fetching on a pseudo-refspec location (refs/changes/), and then cherry-picking it in. Therefore, in order to use one, you need to 1) clone, 2) fetch, and 3) either cherry-pick or checkout (or a couple of other methods). Although you can do this with a little effort with your actual Jenkinsfile (which is configured in the job; you can take the refspec from the environment during a verification and then use “FETCH_HEAD” as your branch), these are not intuitively available for the shared-libraries that you might be importing into your pipeline.

It turns out that you can massage the on-the-fly library loader to do this for you.

if (env.GERRIT_PATCHSET_REVISION) {
  echo("Using shared-library for verification.")

  library([
    identifier: 'myLibrary@' + env.GERRIT_PATCHSET_REVISION,
    retriever: modernSCM([
      $class: 'GitSCMSource',
      remote: 'https://repo.host/pipeline/library',
      traits: [
        [$class: 'jenkins.plugins.git.traits.BranchDiscoveryTrait'],
        [
          $class: 'RefSpecsSCMSourceTrait',
          templates: [
            [value: '+refs/heads/*:refs/remotes/@{remote}/*'], 
            [value: "+refs/changes/*:refs/remotes/@{remote}/*"]
          ]
        ]
      ]
    ])
  ])
} else {
  echo("Using shared-library from branch (not a verification).")

  library("myLibrary@" + env.BRANCH_NAME)
}

The principal things to notice are:

  1. We are telling it to bring all of the change-requests into scope (“+refs/changes/:refs/remotes/@{remote}/“).
  2. We are telling Jenkins to import exactly the library version tied to the change (“‘myLibrary@’ + env.GERRIT_PATCHSET_REVISION”). This wouldn’t be accessible without (1).

It works great.

I generated the original version of the code by using the Snippet Generator with the “library” step and then modifying according to the above.

Note that this pipeline can be used both in a multibranch pipeline job context as well as in the normal [single-branch] pipeline job used for verification (because we would only want to kick-off verification jobs just for the branch of the change). env.BRANCH_NAME will automatically be defined in the multibranch context.