1602319847
The author selected the Wikimedia Foundation to receive a donation as part of the Write for DOnations program.
Jenkins is one of the most popular open-source automation servers, often used to orchestrate continuous integration (CI) and/or continuous deployment (CD) workflows.
Configuring Jenkins is typically done manually through a web-based setup wizard; this can be a slow, error-prone, and non-scalable process. You can see the steps involved by following Step 4 — Setting Up Jenkins of the How To Install Jenkins on Ubuntu 18.04 guide. Furthermore, configurations cannot be tracked in a version control system (VCS) like Git, nor be under the scrutiny of any code review process.
In this tutorial, you will automate the installation and configuration of Jenkins using Docker and the Jenkins Configuration as Code (JCasC) method.
Jenkins uses a pluggable architecture to provide most of its functionality. JCasC makes use of the Configuration as Code plugin, which allows you to define the desired state of your Jenkins configuration as one or more YAML file(s), eliminating the need for the setup wizard. On initialization, the Configuration as Code plugin would configure Jenkins according to the configuration file(s), greatly reducing the configuration time and eliminating human errors.
Docker is the de facto standard for creating and running containers, which is a virtualization technology that allows you to run isolated, self-contained applications consistently across different operation systems (OSes) and hardware architectures. You will run your Jenkins instance using Docker to take advantage of this consistency and cross-platform capability.
This tutorial starts by guiding you through setting up JCasC. You will then incrementally add to the JCasC configuration file to set up users, configuration authentication and authorization, and finally to secure your Jenkins instance. After you’ve completed this tutorial, you’ll have created a custom Docker image that is set up to use the Configuration as Code plugin on startup to automatically configure and secure your Jenkins instance.
To complete this tutorial, you will need:
Note: This tutorial is tested on Ubuntu 18.04; however, because Docker images are self-contained, the steps outlined here would work for any OSes with Docker installed.
Using JCasC eliminates the need to show the setup wizard; therefore, in this first step, you’ll create a modified version of the official [jenkins/jenkins](https://hub.docker.com/r/jenkins/jenkins/)
image that has the setup wizard disabled. You will do this by creating a Dockerfile
and building a custom Jenkins image from it.
The jenkins/jenkins
image allows you to enable or disable the setup wizard by passing in a system property named jenkins.install.runSetupWizard
via the JAVA_OPTS
environment variable. Users of the image can pass in the JAVA_OPTS
environment variable at runtime using the [--env](https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file)
flag to docker run
. However, this approach would put the onus of disabling the setup wizard on the user of the image. Instead, you should disable the setup wizard at build time, so that the setup wizard is disabled by default.
You can achieve this by creating a Dockerfile
and using the [ENV](https://docs.docker.com/engine/reference/builder/#env)
instruction to set the JAVA_OPTS
environment variable.
First, create a new directory inside your server to store the files you will be creating in this tutorial:
mkdir -p $HOME/playground/jcasc
Then, navigate inside that directory:
cd $HOME/playground/jcasc
Next, using your editor, create a new file named Dockerfile
:
nano $HOME/playground/jcasc/Dockerfile
Then, copy the following content into the Dockerfile
:
~/playground/jcasc/
FROM jenkins/jenkins:latest
ENV JAVA_OPTS -Djenkins.install.runSetupWizard=false
Here, you’re using the [FROM](https://docs.docker.com/engine/reference/builder/#from)
instruction to specify jenkins/jenkins:latest
as the base image, and the ENV
instruction to set the JAVA_OPTS
environment variable.
Save the file and exit the editor by pressing CTRL+X
followed by Y
.
#docker
1652543820
Background Fetch is a very simple plugin which attempts to awaken an app in the background about every 15 minutes, providing a short period of background running-time. This plugin will execute your provided callbackFn
whenever a background-fetch event occurs.
There is no way to increase the rate which a fetch-event occurs and this plugin sets the rate to the most frequent possible — you will never receive an event faster than 15 minutes. The operating-system will automatically throttle the rate the background-fetch events occur based upon usage patterns. Eg: if user hasn't turned on their phone for a long period of time, fetch events will occur less frequently or if an iOS user disables background refresh they may not happen at all.
:new: Background Fetch now provides a scheduleTask
method for scheduling arbitrary "one-shot" or periodic tasks.
scheduleTask
seems only to fire when the device is plugged into power.stopOnTerminate: false
for iOS.@config enableHeadless
)⚠️ If you have a previous version of react-native-background-fetch < 2.7.0
installed into react-native >= 0.60
, you should first unlink
your previous version as react-native link
is no longer required.
$ react-native unlink react-native-background-fetch
yarn
$ yarn add react-native-background-fetch
npm
$ npm install --save react-native-background-fetch
react-native >= 0.60
react-native >= 0.60
ℹ️ This repo contains its own Example App. See /example
import React from 'react';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
FlatList,
StatusBar,
} from 'react-native';
import {
Header,
Colors
} from 'react-native/Libraries/NewAppScreen';
import BackgroundFetch from "react-native-background-fetch";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
events: []
};
}
componentDidMount() {
// Initialize BackgroundFetch ONLY ONCE when component mounts.
this.initBackgroundFetch();
}
async initBackgroundFetch() {
// BackgroundFetch event handler.
const onEvent = async (taskId) => {
console.log('[BackgroundFetch] task: ', taskId);
// Do your background work...
await this.addEvent(taskId);
// IMPORTANT: You must signal to the OS that your task is complete.
BackgroundFetch.finish(taskId);
}
// Timeout callback is executed when your Task has exceeded its allowed running-time.
// You must stop what you're doing immediately BackgroundFetch.finish(taskId)
const onTimeout = async (taskId) => {
console.warn('[BackgroundFetch] TIMEOUT task: ', taskId);
BackgroundFetch.finish(taskId);
}
// Initialize BackgroundFetch only once when component mounts.
let status = await BackgroundFetch.configure({minimumFetchInterval: 15}, onEvent, onTimeout);
console.log('[BackgroundFetch] configure status: ', status);
}
// Add a BackgroundFetch event to <FlatList>
addEvent(taskId) {
// Simulate a possibly long-running asynchronous task with a Promise.
return new Promise((resolve, reject) => {
this.setState(state => ({
events: [...state.events, {
taskId: taskId,
timestamp: (new Date()).toString()
}]
}));
resolve();
});
}
render() {
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={styles.scrollView}>
<Header />
<View style={styles.body}>
<View style={styles.sectionContainer}>
<Text style={styles.sectionTitle}>BackgroundFetch Demo</Text>
</View>
</View>
</ScrollView>
<View style={styles.sectionContainer}>
<FlatList
data={this.state.events}
renderItem={({item}) => (<Text>[{item.taskId}]: {item.timestamp}</Text>)}
keyExtractor={item => item.timestamp}
/>
</View>
</SafeAreaView>
</>
);
}
}
const styles = StyleSheet.create({
scrollView: {
backgroundColor: Colors.lighter,
},
body: {
backgroundColor: Colors.white,
},
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
color: Colors.black,
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
color: Colors.dark,
},
});
export default App;
In addition to the default background-fetch task defined by BackgroundFetch.configure
, you may also execute your own arbitrary "oneshot" or periodic tasks (iOS requires additional Setup Instructions). However, all events will be fired into the Callback provided to BackgroundFetch#configure
:
scheduleTask
on iOS seems only to run when the device is plugged into power.scheduleTask
on iOS are designed for low-priority tasks, such as purging cache files — they tend to be unreliable for mission-critical tasks. scheduleTask
will never run as frequently as you want.fetch
event is much more reliable and fires far more often.scheduleTask
on iOS stop when the user terminates the app. There is no such thing as stopOnTerminate: false
for iOS.// Step 1: Configure BackgroundFetch as usual.
let status = await BackgroundFetch.configure({
minimumFetchInterval: 15
}, async (taskId) => { // <-- Event callback
// This is the fetch-event callback.
console.log("[BackgroundFetch] taskId: ", taskId);
// Use a switch statement to route task-handling.
switch (taskId) {
case 'com.foo.customtask':
print("Received custom task");
break;
default:
print("Default fetch task");
}
// Finish, providing received taskId.
BackgroundFetch.finish(taskId);
}, async (taskId) => { // <-- Task timeout callback
// This task has exceeded its allowed running-time.
// You must stop what you're doing and immediately .finish(taskId)
BackgroundFetch.finish(taskId);
});
// Step 2: Schedule a custom "oneshot" task "com.foo.customtask" to execute 5000ms from now.
BackgroundFetch.scheduleTask({
taskId: "com.foo.customtask",
forceAlarmManager: true,
delay: 5000 // <-- milliseconds
});
API Documentation
@param {Integer} minimumFetchInterval [15]
The minimum interval in minutes to execute background fetch events. Defaults to 15
minutes. Note: Background-fetch events will never occur at a frequency higher than every 15 minutes. Apple uses a secret algorithm to adjust the frequency of fetch events, presumably based upon usage patterns of the app. Fetch events can occur less often than your configured minimumFetchInterval
.
@param {Integer} delay (milliseconds)
ℹ️ Valid only for BackgroundFetch.scheduleTask
. The minimum number of milliseconds in future that task should execute.
@param {Boolean} periodic [false]
ℹ️ Valid only for BackgroundFetch.scheduleTask
. Defaults to false
. Set true to execute the task repeatedly. When false
, the task will execute just once.
@config {Boolean} stopOnTerminate [true]
Set false
to continue background-fetch events after user terminates the app. Default to true
.
@config {Boolean} startOnBoot [false]
Set true
to initiate background-fetch events when the device is rebooted. Defaults to false
.
❗ NOTE: startOnBoot
requires stopOnTerminate: false
.
@config {Boolean} forceAlarmManager [false]
By default, the plugin will use Android's JobScheduler
when possible. The JobScheduler
API prioritizes for battery-life, throttling task-execution based upon device usage and battery level.
Configuring forceAlarmManager: true
will bypass JobScheduler
to use Android's older AlarmManager
API, resulting in more accurate task-execution at the cost of higher battery usage.
let status = await BackgroundFetch.configure({
minimumFetchInterval: 15,
forceAlarmManager: true
}, async (taskId) => { // <-- Event callback
console.log("[BackgroundFetch] taskId: ", taskId);
BackgroundFetch.finish(taskId);
}, async (taskId) => { // <-- Task timeout callback
// This task has exceeded its allowed running-time.
// You must stop what you're doing and immediately .finish(taskId)
BackgroundFetch.finish(taskId);
});
.
.
.
// And with with #scheduleTask
BackgroundFetch.scheduleTask({
taskId: 'com.foo.customtask',
delay: 5000, // milliseconds
forceAlarmManager: true,
periodic: false
});
@config {Boolean} enableHeadless [false]
Set true
to enable React Native's Headless JS mechanism, for handling fetch events after app termination.
index.js
(MUST BE IN index.js
):import BackgroundFetch from "react-native-background-fetch";
let MyHeadlessTask = async (event) => {
// Get task id from event {}:
let taskId = event.taskId;
let isTimeout = event.timeout; // <-- true when your background-time has expired.
if (isTimeout) {
// This task has exceeded its allowed running-time.
// You must stop what you're doing immediately finish(taskId)
console.log('[BackgroundFetch] Headless TIMEOUT:', taskId);
BackgroundFetch.finish(taskId);
return;
}
console.log('[BackgroundFetch HeadlessTask] start: ', taskId);
// Perform an example HTTP request.
// Important: await asychronous tasks when using HeadlessJS.
let response = await fetch('https://reactnative.dev/movies.json');
let responseJson = await response.json();
console.log('[BackgroundFetch HeadlessTask] response: ', responseJson);
// Required: Signal to native code that your task is complete.
// If you don't do this, your app could be terminated and/or assigned
// battery-blame for consuming too much time in background.
BackgroundFetch.finish(taskId);
}
// Register your BackgroundFetch HeadlessTask
BackgroundFetch.registerHeadlessTask(MyHeadlessTask);
@config {integer} requiredNetworkType [BackgroundFetch.NETWORK_TYPE_NONE]
Set basic description of the kind of network your job requires.
If your job doesn't need a network connection, you don't need to use this option as the default value is BackgroundFetch.NETWORK_TYPE_NONE
.
NetworkType | Description |
---|---|
BackgroundFetch.NETWORK_TYPE_NONE | This job doesn't care about network constraints, either any or none. |
BackgroundFetch.NETWORK_TYPE_ANY | This job requires network connectivity. |
BackgroundFetch.NETWORK_TYPE_CELLULAR | This job requires network connectivity that is a cellular network. |
BackgroundFetch.NETWORK_TYPE_UNMETERED | This job requires network connectivity that is unmetered. Most WiFi networks are unmetered, as in "you can upload as much as you like". |
BackgroundFetch.NETWORK_TYPE_NOT_ROAMING | This job requires network connectivity that is not roaming (being outside the country of origin) |
@config {Boolean} requiresBatteryNotLow [false]
Specify that to run this job, the device's battery level must not be low.
This defaults to false. If true, the job will only run when the battery level is not low, which is generally the point where the user is given a "low battery" warning.
@config {Boolean} requiresStorageNotLow [false]
Specify that to run this job, the device's available storage must not be low.
This defaults to false. If true, the job will only run when the device is not in a low storage state, which is generally the point where the user is given a "low storage" warning.
@config {Boolean} requiresCharging [false]
Specify that to run this job, the device must be charging (or be a non-battery-powered device connected to permanent power, such as Android TV devices). This defaults to false.
@config {Boolean} requiresDeviceIdle [false]
When set true, ensure that this job will not run if the device is in active use.
The default state is false: that is, the for the job to be runnable even when someone is interacting with the device.
This state is a loose definition provided by the system. In general, it means that the device is not currently being used interactively, and has not been in use for some time. As such, it is a good time to perform resource heavy jobs. Bear in mind that battery usage will still be attributed to your application, and shown to the user in battery stats.
Method Name | Arguments | Returns | Notes |
---|---|---|---|
configure | {FetchConfig} , callbackFn , timeoutFn | Promise<BackgroundFetchStatus> | Configures the plugin's callbackFn and timeoutFn . This callback will fire each time a background-fetch event occurs in addition to events from #scheduleTask . The timeoutFn will be called when the OS reports your task is nearing the end of its allowed background-time. |
scheduleTask | {TaskConfig} | Promise<boolean> | Executes a custom task. The task will be executed in the same Callback function provided to #configure . |
status | callbackFn | Promise<BackgroundFetchStatus> | Your callback will be executed with the current status (Integer) 0: Restricted , 1: Denied , 2: Available . These constants are defined as BackgroundFetch.STATUS_RESTRICTED , BackgroundFetch.STATUS_DENIED , BackgroundFetch.STATUS_AVAILABLE (NOTE: Android will always return STATUS_AVAILABLE ) |
finish | String taskId | Void | You MUST call this method in your callbackFn provided to #configure in order to signal to the OS that your task is complete. iOS provides only 30s of background-time for a fetch-event -- if you exceed this 30s, iOS will kill your app. |
start | none | Promise<BackgroundFetchStatus> | Start the background-fetch API. Your callbackFn provided to #configure will be executed each time a background-fetch event occurs. NOTE the #configure method automatically calls #start . You do not have to call this method after you #configure the plugin |
stop | [taskId:String] | Promise<boolean> | Stop the background-fetch API and all #scheduleTask from firing events. Your callbackFn provided to #configure will no longer be executed. If you provide an optional taskId , only that #scheduleTask will be stopped. |
BGTaskScheduler
API for iOS 13+[||]
button to initiate a Breakpoint.(lldb)
, paste the following command (Note: use cursor up/down keys to cycle through previously run commands):e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.transistorsoft.fetch"]
[ > ]
button to continue. The task will execute and the Callback function provided to BackgroundFetch.configure
will receive the event.BGTaskScheduler
api supports simulated task-timeout events. To simulate a task-timeout, your fetchCallback
must not call BackgroundFetch.finish(taskId)
:let status = await BackgroundFetch.configure({
minimumFetchInterval: 15
}, async (taskId) => { // <-- Event callback.
// This is the task callback.
console.log("[BackgroundFetch] taskId", taskId);
//BackgroundFetch.finish(taskId); // <-- Disable .finish(taskId) when simulating an iOS task timeout
}, async (taskId) => { // <-- Event timeout callback
// This task has exceeded its allowed running-time.
// You must stop what you're doing and immediately .finish(taskId)
print("[BackgroundFetch] TIMEOUT taskId:", taskId);
BackgroundFetch.finish(taskId);
});
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateExpirationForTaskWithIdentifier:@"com.transistorsoft.fetch"]
BackgroundFetch
APIDebug->Simulate Background Fetch
$ adb logcat
:$ adb logcat *:S ReactNative:V ReactNativeJS:V TSBackgroundFetch:V
21+
:$ adb shell cmd jobscheduler run -f <your.application.id> 999
<21
, simulate a "Headless JS" event with (insert <your.application.id>)$ adb shell am broadcast -a <your.application.id>.event.BACKGROUND_FETCH
Download Details:
Author: transistorsoft
Source Code: https://github.com/transistorsoft/react-native-background-fetch
License: MIT license
1604048400
The story of Softagram is a long one and has many twists. Everything started in a small company long time ago, from the area of static analysis tools development. After many phases, Softagram is focusing on helping developers to get visual feedback on the code change: how is the software design evolving in the pull request under review.
While it is trivial to write 20 KLOC apps without help of tooling, usually things start getting complicated when the system grows over 100 KLOC.
The risk of god class anti-pattern, and the risk of mixing up with the responsibilities are increasing exponentially while the software grows larger.
To help with that, software evolution can be tracked safely with explicit dependency change reports provided automatically to each pull request. Blocking bad PR becomes easy, and having visual reports also has a democratizing effect on code review.
Architectural analysis of the code, identifying how delta is impacting to the code base. Language specific analyzers are able to extract the essential internal/external dependency structures from each of the mainstream programming languages.
Checking for rule violations or anomalies in the delta, e.g. finding out cyclical dependencies. Graph theory comes to big help when finding out unwanted or weird dependencies.
Building visualization for humans. Complex structures such as software is not easy to represent without help of graph visualization. Here comes the vital role of change graph visualization technology developed within the last few years.
#automated-code-review #code-review-automation #code-reviews #devsecops #software-development #code-review #coding #good-company
1595494800
Welcome back to the second article in our #BacktoBasics series. As many of us already know, SonarQube is an open-source tool for continuous inspection of code quality. It performs static analysis of code, thus detecting bugs, code smells and security vulnerabilities. In addition, it also can report on the duplicate code, unit tests, code coverage and code complexities for multiple programming languages. Hence, in order to achieve Continuous Integration with fully automated code analysis, it is important to integrate SonarQube with CI tools such as Jenkins. Here, we are going to discuss integrating SonarQube with Jenkins to perform code analysis.
Enough on the introductions. Let’s jump into the configurations, shall we? First of all, let’s spin up Jenkins and SonarQube using Docker containers. Note that, we are going to use docker compose as it is an easy method to handle multiple services. Below is the content of the docker-compose.yml
file which we are going to use.
docker-compose.yml file
version: '3'
services:
sonarqube:
ports:
- '9000:9000'
volumes:
- 'E:\work\sonar\conf\:/opt/sonarqube/conf'
- 'E:\work\sonar\data\:/opt/sonarqube/data'
- 'E:\work\sonar\logs\:/opt/sonarqube/logs'
- 'E:\work\sonar\extensions\:/opt/sonarqube/extensions'
image: sonarqube
jenkins:
image: 'ravindranathbarathy/jenkins'
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- 'E:\work\jenkins_home\:/var/jenkins_home'
ports:
- '8080:8080'
- '5000:50000'
jenkins-slave:
container_name: jenkins-slave
restart: always
environment:
- 'JENKINS_URL=http://jenkins:8080'
image: kaviyakulothungan/jenkins-slave-node:v2
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- 'E:\work\jenkins_slave\:/home/jenkins'
depends_on:
- jenkins
docker-compose up
is the command to run the docker-compose.yml
file.
docker-compose command to spin up Jenkins and Sonarqube
Shell
1
docker-compose up
Note: The _docker-compose_
command must be run from folder where the _docker-compose.yml_
file is placed
This file, when run, will automatically host the Jenkins listening on port 8080 along with a slave.
Jenkins hosted using Docker
The SonarQube will be hosted listening on port 9000.
SonarQube hosted using Docker
In order to run the SonarQube analysis in Jenkins, there are few things we have to take care before creating the Jenkins job. First of all, we need to install the**_ ‘_SonarQube Scanner” plugin. For this, let’s go to Jenkins -> Manage Jenkins -> Manage Plugins. There, navigate to “Available” view and look for the plugin “SonarQube Scanner”. Select the plugin and click on “Install without restart**” and wait for the plugin to be installed.
Installing SonarQube Scanner Plugin
Once the plugin is installed, we need to configure a few things in the Jenkins global configuration page.
For that, let’s click on Jenkins -> Manage Jenkins -> Configure System -> SonarQube Servers and fill in the required details.
SonarQube Server Configuration
Here,
To get the server authentication token, login to SonarQube and go to Administration -> Security -> Users and then click on Tokens. There, Enter a Token name and click on Generate and copy the token value and paste it in the Jenkins field and then click on “Done”.
Creating Authorization Token
Finally, save the Jenkins Global configurations by clicking on the “Save” icon.
There is one last configuration which has to be set up. In order to run SonarQube scan for our project, we need to install and configure the SonarQube scanner in our Jenkins. For that, let’s go to Manage Jenkins -> Global Tool Configuration -> SonarQube Scanner -> SonarQube Scanner installations. Enter any meaningful name under the Name field and select an appropriate method in which you want to install this tool in Jenkins. Here, we are going to select “Install automatically” option. Then, click on “Save”.
SonarQube Scanner Configuration in Jenkins
Since we are all set with the global configurations, let’s now create a Jenkins Pipeline Job for a simple node.js application for which code analysis will be done by SonarQube.
For that, let’s click on “New Item” in Jenkins home page and enter the job name as “sonarqube_test_pipeline” and then select the “Pipeline” option and then click on “OK”.
Creating Jenkins Pipeline job
Now, inside the job configuration, let’s go to the Pipeline step and select Pipeline Script from SCM and then select Git and enter the Repository URL and then save the job.
##backtobasics #continuous integration #devops #blueocean #ci #code review #continous integration #docker #docker-compose #git #github #jenkins #jenkins pipeline #nodejs #sonarqube #sonarqube scanner #static code analysis
1604008800
Static code analysis refers to the technique of approximating the runtime behavior of a program. In other words, it is the process of predicting the output of a program without actually executing it.
Lately, however, the term “Static Code Analysis” is more commonly used to refer to one of the applications of this technique rather than the technique itself — program comprehension — understanding the program and detecting issues in it (anything from syntax errors to type mismatches, performance hogs likely bugs, security loopholes, etc.). This is the usage we’d be referring to throughout this post.
“The refinement of techniques for the prompt discovery of error serves as well as any other as a hallmark of what we mean by science.”
We cover a lot of ground in this post. The aim is to build an understanding of static code analysis and to equip you with the basic theory, and the right tools so that you can write analyzers on your own.
We start our journey with laying down the essential parts of the pipeline which a compiler follows to understand what a piece of code does. We learn where to tap points in this pipeline to plug in our analyzers and extract meaningful information. In the latter half, we get our feet wet, and write four such static analyzers, completely from scratch, in Python.
Note that although the ideas here are discussed in light of Python, static code analyzers across all programming languages are carved out along similar lines. We chose Python because of the availability of an easy to use ast
module, and wide adoption of the language itself.
Before a computer can finally “understand” and execute a piece of code, it goes through a series of complicated transformations:
As you can see in the diagram (go ahead, zoom it!), the static analyzers feed on the output of these stages. To be able to better understand the static analysis techniques, let’s look at each of these steps in some more detail:
The first thing that a compiler does when trying to understand a piece of code is to break it down into smaller chunks, also known as tokens. Tokens are akin to what words are in a language.
A token might consist of either a single character, like (
, or literals (like integers, strings, e.g., 7
, Bob
, etc.), or reserved keywords of that language (e.g, def
in Python). Characters which do not contribute towards the semantics of a program, like trailing whitespace, comments, etc. are often discarded by the scanner.
Python provides the tokenize
module in its standard library to let you play around with tokens:
Python
1
import io
2
import tokenize
3
4
code = b"color = input('Enter your favourite color: ')"
5
6
for token in tokenize.tokenize(io.BytesIO(code).readline):
7
print(token)
Python
1
TokenInfo(type=62 (ENCODING), string='utf-8')
2
TokenInfo(type=1 (NAME), string='color')
3
TokenInfo(type=54 (OP), string='=')
4
TokenInfo(type=1 (NAME), string='input')
5
TokenInfo(type=54 (OP), string='(')
6
TokenInfo(type=3 (STRING), string="'Enter your favourite color: '")
7
TokenInfo(type=54 (OP), string=')')
8
TokenInfo(type=4 (NEWLINE), string='')
9
TokenInfo(type=0 (ENDMARKER), string='')
(Note that for the sake of readability, I’ve omitted a few columns from the result above — metadata like starting index, ending index, a copy of the line on which a token occurs, etc.)
#code quality #code review #static analysis #static code analysis #code analysis #static analysis tools #code review tips #static code analyzer #static code analysis tool #static analyzer
1595249460
Following the second video about Docker basics, in this video, I explain Docker architecture and explain the different building blocks of the docker engine; docker client, API, Docker Daemon. I also explain what a docker registry is and I finish the video with a demo explaining and illustrating how to use Docker hub
In this video lesson you will learn:
#docker #docker hub #docker host #docker engine #docker architecture #api