Saturday, August 3, 2024

MacOs Terminal call

Hello everyone, 

In this quick tutorial i will show you how to be able to call from Mac terminal some useful tools like : VScode , Sublime Text and Sublime Merge.

VScode is quite straight forward, hold 'cmd + shit + P' then look for Shell command: install 'code' command in PATH.


Once you click on it will be configured.


For Sublime Text and Sublime merge, once they are downloaded and installed in Application folder (https://www.sublimemerge.com/ , https://www.sublimetext.com/)

Create links of their binaries into a path mentioned in your PATH variable (ex: /usr/local/bin/)


>. ln -s "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl" /usr/local/bin/stxt 


>. ln -s "/Applications/Sublime Merge.app/Contents/SharedSupport/bin/smerge" /usr/local/bin/smerge


Once set, you can call them from your terminal.


% code --help

Visual Studio Code 1.91.0


Usage: code [options][paths...]


To read from stdin, append '-' (e.g. 'ps aux | grep code | code -')


Options

  -d --diff <file> <file>                    Compare two files with each other.

  -m --merge <path1> <path2> <base> <result> Perform a three-way merge by providing paths for two modified versions of a file, the common origin of both modified

                                             versions and the output file to save merge results.

  -a --add <folder>                          Add folder(s) to the last active window.

  -g --goto <file:line[:character]>          Open a file at the path on the specified line and character position.

  -n --new-window                            Force to open a new window.

  -r --reuse-window                          Force to open a file or folder in an already opened window.

  -w --wait                                  Wait for the files to be closed before returning.

  --locale <locale>                          The locale to use (e.g. en-US or zh-TW).

  --user-data-dir <dir>                      Specifies the directory that user data is kept in. Can be used to open multiple distinct instances of Code.

  --profile <profileName>                    Opens the provided folder or workspace with the given profile and associates the profile with the workspace. If the

                                             profile does not exist, a new empty one is created.

  -h --help                                  Print usage.



% smerge --help

Sublime Merge build 2096


Usage: smerge path               Open the given repository

   or: smerge search query       Search for commits in the current repository

   or: smerge blame file [line]  Blame the given file in the current repository

   or: smerge log file           Show the file history in the current repository

   or: smerge mergetool          Opens the merge tool for the given files 

         [--no-wait] [base] left right [-o merged]


  -n or --new-window:      Open a new window

  --launch-or-new-window:  Only open a new window if the application is running

  -b or --background:      Don't activate the application

  --safe-mode:             Launch using a sandboxed (clean) environment

  -h or --help:            Show help (this message) and exit

  -v or --version:         Show version and exit



% stxt --help

Sublime Text build 4169


Usage: stxt [arguments] [files]         Edit the given files

   or: stxt [arguments] [directories]   Open the given directories

   or: stxt [arguments] -- [files]      Edit files that may start with '-'

   or: stxt [arguments] -               Edit stdin

   or: stxt [arguments] - >out          Edit stdin and write the edit to stdout


Arguments:

  --project <project>:    Load the given project

  --command <command>:    Run the given command

  -n or --new-window:     Open a new window

  --launch-or-new-window: Only open a new window if the application is open

  -a or --add:            Add folders to the current window

  -w or --wait:           Wait for the files to be closed before returning

  -b or --background:     Don't activate the application

  -s or --stay:           Keep the application activated after closing the file

  --safe-mode:            Launch using a sandboxed (clean) environment

  -h or --help:           Show help (this message) and exit

  -v or --version:        Show version and exit


--wait is implied if reading from stdin. Use --stay to not switch back

to the terminal when a file is closed (only relevant if waiting for a file).


Filenames may be given a :line or :line:column suffix to open at a specific

location.




enjoy ;).


 

Docker for Mac tutorial


Hello Everyone :)

In this this tutorial I'm going to show you guys how to install docker on mac os system. for those who don't know what docker is, docker is a container manager that allows the user to have an integrated and consistent environments between the development, test and the production environments. so to avoid having this kind of conversation.

" user : the bug is still persistent in the production environment
developer : the application works fine for me there is no bug ! "


with docker all the environments are configured the same.

to "dockerise" your environment, let's start by downloading docker  , download the dmg file and then execute it, once done let's have a sample application to dockerise :

Let's build a simple html page for our example with php that is going to show a list of objects (a list cars for example) , and a api application developed with Python that will exposes the rest endpoints.

we are going to see the concept of volumes , images and containers throughout this tutorial.

let's star coding ..

The overall files structure of the project would looks like this : 

docker-tuto-folder | -----> | app1 |----> Dockerfile
                                   |----> src ----> | index.php

                   | -----> | app2 |----> Dockerfile
                                   |----> src ----> | app.py


After downloading your docker desktop, install it in your mac
 
let's start app1
app1/Dockerfile : 
FROM php:7.0-apache
COPY src/ /var/www/html
EXPOSE 80

FROM php:7.0-apache -> download php image 
COPY src/ /var/www/html  -> copy the content of src (path of src is relative to where the Dockerfile is) file from the the host machine folder into the /var/ww/html folder inside the container's folder
EXPOSE 80 -> make sure to open port 80 so you can access thought the browser

The Docker file represent the environement that you want to run. Once it is built, it will create the image (for app1). This image will be the blueprint (or the template) for the creation of the containers (executables) . Keep in mind that the container is the instantiation of the image.
It's always a best practice to have each micro service goes in a single container.


let's put some content in the index.php
<html>
<header></header>
<body>
<h2>Hello world</h2>
<marquee>Hello world</marquee>
</body>
</html>

Once done let's create the image for app1 with Docker build command : 
>. 'Docker build -t hello-world .'   -> building the image based on the php official image. And name it hello-world and pass the path of the Dockerfile '.' which is in the current folder. 

Use this command to see the list of images in your local repository.
>. Docker images 

To create your container , use Docker run , it will create a container based on the image and run it :
>. Docker run -p 80:80 hello-world

-p 80:80 (forward the port 80 from the host (1st one) to the port 80 of the container (2nd one)) 


Open browser with localhost:80 and see the html page that you have created 


If we put some modification in the code the result is not automatic we have to kill the container and rebuild it  , which is a pain and a lot of resources being consumed


To do so we use shared volume , there are 2 types : 
  •  shared volume between containers 
  •  shared volume with the host (we are going to use this one )
With the shared volume every modification can instantly being shown on the result , the container will have an access to our code folders to pick the sources


To do so : use -v option to mount the volume like this : 

>. docker run -p 80:80 -v /yourpath/docker-tuto-folder/app1/src/:/var/www/html/ hello-world





For app2 let's create a python script for it :
 
from flask import Flask, jsonify

app = Flask(__name__)

# Sample data: list of car objects
cars = [
{"id": 1, "make": "Toyota", "model": "Corolla", "year": 2020},
{"id": 2, "make": "Honda", "model": "Civic", "year": 2019},
{"id": 3, "make": "Ford", "model": "Mustang", "year": 2021},
{"id": 4, "make": "Chevrolet", "model": "Camaro", "year": 2022},
{"id": 5, "make": "Ford", "model": "Focus", "year": 2015}
]

# Route to return the list of cars
@app.route('/cars', methods=['GET'])
def get_cars():
return jsonify(cars)

if __name__ == '__main__':
app.run(debug=True)

it's a simple app that uses flask framework for web development. The app exposes a res api that returns a list of cars through the end point /cars.


Then create the Dockerfile With :

FROM python:3.9-slim
WORKDIR /app
COPY src/ /app
RUN pip install flask
EXPOSE 5000
ENV FLASK_APP=app.py
CMD [ "python", "-m" , "flask", "run", "--host=0.0.0.0"]

The docker files says to create an environment based on python:3.9-slim image (the official python image), set the working directory of the python app into /app , copy files from src folder and past them into the working directory , install the necessary dependency for flask web server to work , exposes the port on which the app will communicate , set a necessary environment variable in order for flask to work and finally the set the command that is going to be executed inside the container once this one is created and launched.

Then we can use docker build and docker run with various arguments but it so painful when you have a lot of service hence a lot of container.
To handle this problematic we have docker compose :D
Docker compose allows to define all the container in a single configuration file.
And then they can be started and stop all at once. 


Let's create a docker-compose.yml file 


docker-tuto-folder | -----> | app1 |----> Dockerfile
                                   |----> src ----> | index.php

                   | -----> | app2 |----> Dockerfile
                                   |----> src ----> | app.py
                   
                   | -----> | docker-compose.yml

docker-compose.yml :
version: '3'

services:
app2-service:
build: ./app2
image: hello-cars:latest
container_name: app2-api
volumes:
- ./app2/src:/app
ports:
- 5000:5000

app1-service:
build: ./app1
image: hello-world:latest
container_name: app1-php
volumes:
- ./app1/src:/var/www/html
ports:
- 80:80
depends_on:
- app2-service

Make sure to not have tabulation/space in the file before the ‘ : ’ characters


VERSION :’3’-> version format of the file latest one is 3

services:
app2-service: (the service name , the file allows to define many services each reference a dockerfile)
build: ./app2 (where the Dockerfile is present)
  image: hello-cars:latest (specify the image name that is going to be used)
  container_name: app2-api (specify the container name that is going to be used)
volumes:
- ./product:/usr/src/app. -> use ‘-‘ to specify a list of parameter here only one  , the    volume mapping
ports:
- 5001:80 —> port mapping 

 app1-service:
  build: ./app1
  image: hello-world:latest
  container_name: app1-php
  volumes:
   - ./app1/src:/var/www/html
  ports:
   - 80:80
  depends_on:
   - app2-service



Making sure that app1 module is dependent on the app2-service module (see last instruction line in the config file)

Launch : docker-compose up  to see the application running with no painful pre configuration  to do just run 

>. docker-compose up 

You can run it with detach mode ‘ docker-compose up -d ‘ the service will run in background mode .

You can then check on them the following commands :

>. Docker ps 


You can stop them with 

>. docker compose down 






Now let's make the php page get the data from python endpoint. the two apps are into separate containers (two separate context) they can't communicate with each other unless a communication medium is established between them. Docker containers can communcate through shared files/folder through the host or through virtual network.

In Our example we are going to set a network (bridge network) between the two containers in order to establish the communication between app1 and app2.

First let's update the Docker compose by adding the network configuration :
networks:
app-network:
name: app-network
driver: bridge

This configuration tells Docker to create a virtual network of type bridge called app-network.
Then we need to connect the services into that network.
The Docker compose file would looks like this : 

version: '3'

services:
app2-service:
build: ./app2
image: hello-cars:latest
container_name: app2-api
volumes:
- ./app2/src:/app
ports:
- 5006:5000
networks:
- app-network

app1-service:
build: ./app1
image: hello-world:latest
container_name: app1-php
volumes:
- ./app1/src:/var/www/html
ports:
- 82:80
depends_on:
- app2-service
networks:
- app-network

networks:
app-network:
name: app-network
driver: bridge



In every module a networks param is added where it's mentioned that it should be connected to the bridge network that we created in the bottom of the file.

After update the docker compose file let's run 
>. docker compose down 
>. docker compose up --build

And make sure that network has been created and both of the modules (app1 , app2) are connected to it 

>. docker network inspect app-network



After setting the docker configuration we can update the index.php file by adding this sample code into the body tag. this piece of code is going to call the api show the data in the page
<?php
// URL of the Flask API
$api_url = 'http://172.18.0.2:5000/cars';

// Initialize a cURL session
$curl = curl_init($api_url);

// Set cURL options
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPGET, true);

// Execute the cURL request and get the response
$response = curl_exec($curl);

// Check for cURL errors
if ($response === false) {
echo "cURL Error: " . curl_error($curl);
} else {
// Decode the JSON response
$data = json_decode($response, true);

// Display the data as-is
echo '<pre>';
print_r($data);
echo '</pre>';
}

// Close the cURL session
curl_close($curl);
?> 

Note that api_url uses the internal ip of the app2 module calling the internal port 5000 , use the generated IP you have.

$api_url = 'http://172.18.0.2:5000/cars';


Once executed we can see the result on the page :




enjoy ;)




some useful commands : 

>. docker build -t hello-cars .
>. docker run -p 5003:5000 hello-cars

>. docker logs -f <id-container>
>. docker image remove <id-image> -f

>. docker run -d -p 5004:5000 --name hello-cars-ct hello-cars
    (you can name you container in order not deal with ids)
>. docker stop hello-cars-ct