montana

Since
9 Snippets
  • Detect OS in Go

    package main
    
    import (
        "fmt"
        "runtime"
    )
    
    func main() {
        // The runtime.GOOS constant can be used to detect the OS at runtime,
        // since this constant is only set at runtime.
        os := runtime.GOOS
    
        switch os {
        case "windows":
            fmt.Println("Windows")
        case "darwin":
            fmt.Println("MacOS")
        case "linux":
            fmt.Println("Linux")
        default:
            fmt.Printf("%s.\n", os)
        }
    
        // The runtime.GOARCH constant can be used to determine the target architecture of a running program.
        fmt.Println(runtime.GOARCH)
    }
    
    // Output:
    // Linux
    // amd64

    GOOS constant to determine the operating system your Go program is running on. Here's an example of how to check the operating system in Go.

  • Create temporary file or directory in Go

    package main
    
    import (
        "fmt"
        "os"
        "path/filepath"
    )
    
    func checkErr(err error) {
        if err != nil {
            panic(err)
        }
    }
    
    func main() {
        // The simplest way to create a temporary file is to call os.CreateTemp.
        // It will create and open the file for reading and writing.
        // We used "" as the first argument, so os.CreateTemp will create a file in the default directory.
        tmpFile, err := os.CreateTemp("", "tmpfile")
        checkErr(err)
        defer os.Remove(tmpFile.Name())
    
        fmt.Println("Temp file name:", tmpFile.Name())
    
        // Write some data to the temporary file
        _, err = tmpFile.Write([]byte{1, 2, 3, 4, 5})
        checkErr(err)
    
        // If we intend to write a lot of temporary files, we may prefer to create a temporary directory.
        // The arguments to os.MkdirTemp are the same as for os.CreateTemp, but it returns the directory name rather than the opened file.
        dName, err := os.MkdirTemp("", "tmpdir")
        checkErr(err)
        defer os.RemoveAll(dName)
        
        fmt.Println("Temp directory name:", dName)
    
        fName := filepath.Join(dName, "testFile")
        err = os.WriteFile(fName, []byte{1, 2, 3, 4, 5}, 0666)
        checkErr(err)
        defer os.Remove(fName)
    }
    
    // Output:
    // Temp file name: /tmp/tmpfile3400905374
    // Temp directory name: /tmp/tmpdir2812568099

    During program execution, we often want to create data that is not needed after the program exits. Temporary files and directories are useful for this purpose because they do not pollute the file system over time.

  • Context manager in Python

    # File management using context manager
    class FileManager():
        def __init__(self, filename, mode):
            self.filename = filename
            self.mode = mode
            self.file = None
      
        # The __enter__ method opens the file and returns a file object
        def __enter__(self):
            print('Open file: {}'.format(self.filename))
            self.file = open(self.filename, self.mode)
            return self.file
    
        # The __exit__ method takes care of closing the file on exiting the with block 
        def __exit__(self, etype, value, traceback):
            print('Close file: {}'.format(self.filename))
            self.file.close()
    
    # A FileManager object is created with test.txt as the filename and "write" mode
    # when __init__ method is executed
    with FileManager('test.txt', 'w') as f:
        f.write('First line\n')
        f.write('Second line\n')
    
    # The file is already closed thanks to the automatic call to the __exit__ method
    print('File closed: {}\n'.format(f.closed))
    
    with FileManager('test.txt', 'r') as f:
        for line in f:
            print(line.rstrip())
    
    # Output
    #Open file: test.txt
    #Close file: test.txt
    #File closed: True
    #
    #Open file: test.txt
    #First line
    #Second line
    #Close file: test.txt

    When creating context managers using classes, be sure to ensure that the class includes methods: __enter__() and __exit__(). The __enter__() method provides a resource to be managed, and __exit__() performs cleanup operations without returning any value. To understand the basic structure of building context managers using classes, let's look at a simple FileManager class for managing files.

  • Writing files in Go

    package main
    
    import (
        "bufio"
        "fmt"
        "os"
    )
    
    func checkErr(err error) {
        if err != nil {
            panic(err)
        }
    }
    
    func main() {
        content := "Some content"
        // write a string (or just bytes) into a file
        err := os.WriteFile("/tmp/dfile1", []byte(content), 0644)
        checkErr(err)
    
        // open a file for writing
        file, err := os.Create("/tmp/dfile2")
        checkErr(err)
        // defer a Close immediately after opening a file
        defer file.Close()
    
        bytesCount, err := file.Write([]byte(content))
        checkErr(err)
        fmt.Printf("wrote %d bytes\n", bytesCount)
    
        bytesCount, err = file.WriteString("Some other content\n")
        checkErr(err)
        fmt.Printf("wrote %d bytes\n", bytesCount)
        // flush writes to a stable storage (file system for example)
        file.Sync()
    
        // bufio provides buffered writers
        writer := bufio.NewWriter(file)
        bytesCount, err = writer.WriteString("Some othe buffered content\n")
        checkErr(err)
        fmt.Printf("wrote %d bytes\n", bytesCount)
        // ensure all buffered operations have been applied to the underlying writer
        writer.Flush()
    }

    Here are examples of writing data to files using Go.

  • How Select on Channel Works in Golang

    package main
    
    import (
        "fmt"
        "time"
    )
    
    func main() {
        // in this example we will choose between two channels
        c1 := make(chan string)
        c2 := make(chan string)
    
        go func() {
            time.Sleep(1 * time.Second)
            c1 <- "one"
        }()
    
        // each channel will receive a value after some time
        go func() {
            time.Sleep(2 * time.Second)
            c2 <- "two"
        }()
    
        // use select statement to wait for both values ​​at the same time,
        // printing each one as it arrives
        for i := 0; i < 2; i++ {
            select {
            case msg1 := <-c1:
                fmt.Println("received", msg1)
            case msg2 := <-c2:
                fmt.Println("received", msg2)
            }
        }
    }

    Select statement allows you to wait for multiple operations on a channel.

  • Worker pools in Go

    package main
    
    import (
        "fmt"
        "time"
    )
    
    // this is a worker that we will run in several parallel instances
    // these workers will receive tasks through the 'jobs' channel and send the results to 'results'
    // we will wait for one second for each task to simulate heavy requests
    func worker(id int, jobs <-chan int, results chan<- int) {
        for j := range jobs {
            fmt.Println("worker", id, "started job", j)
            time.Sleep(time.Second)
            fmt.Println("worker", id, "finished job", j)
            results <- j * 2
        }
    }
    
    func main() {
        // to use worker pool, we need to send a task and receive the execution results
        // therefore 2 channels are created
        jobs := make(chan int, 100)
        results := make(chan int, 100)
    
        // start 3 workers, initially blocked because no assignments yet
        for w := 1; w <= 3; w++ {
            go worker(w, jobs, results)
        }
    
        // send 5 jobs and then close the channel, notofying that all jobs have been sent
        for j := 1; j <= 5; j++ {
            jobs <- j
        }
    
        close(jobs)
    
        // collect all the results
        // this also ensures that the goroutines have ended
        for a := 1; a <= 5; a++ {
            <-results
        }
    }

    This example shows how to implement a worker pool using channels and goroutines.

  • Channel synchronization in Go

    package main
    
    import (
        "fmt"
        "time"
    )
    
    // the channel is used to notify main goroutine that the function completed successfully
    func worker(done chan bool) {
        fmt.Println("working...")
        time.Sleep(time.Second)
        fmt.Println("done")
    
        done <- true // send a value to indicate that the function completed successfully
    }
    
    func main() {
        done := make(chan bool, 1) // create a buffered channel for notification
        go worker(done) // run worker
    
        <-done // blocked until a notification is received from the worker from the channel
               // if you remove the line <- done the program will close before the worker starts
    }

    Channels can be used to synchronize execution between goroutines. Here is an example of using a channel to wait for a goroutine to complete.

  • Check if a file exists or not in Go

    package main
    
    import (
    	"errors"
    	"fmt"
    	"os"
    )
    
    func main() {
    	filePath := "file.txt"
    
    	if _, err := os.Stat(filePath); errors.Is(err, os.ErrNotExist) {
    		fmt.Println("file not exists")
    	} else {
    		fmt.Println("file exists")
    	}
    }
  • How to detect OS in bash script?

    #!/bin/bash
    
    die()
    {
        echo "ERROR: $*" >&2
        exit 1
    }
    
    detect_os ()
    {
        OS="$(uname -s)"
        ARCH="$(uname -m)"
    
        case "$OS" in
            Linux)
                if [ -e /etc/lsb-release ]; then
                    source /etc/lsb-release
    
                    DIST_ID="${DISTRIB_ID}"
                    OS_VERSION="${DISTRIB_RELEASE}"
                    OS_CODENAME="${DISTRIB_CODENAME}"
                elif [ -e /etc/os-release]; then
                    source /etc/os-release
    
                    DIST_ID="${ID}"
                    OS_VERSION="${VERSION_ID}"
                    OS_CODENAME="${VERSION_CODENAME}"
    
                elif [ $(which lsb_release 2>/dev/null) ]; then
                    DIST_ID="$(lsb_release -s -i)"
                    OS_VERSION="$(lsb_release -s -r)"
                    OS_CODENAME="$(lsb_release -s -c)"
                else
                    die "Colud not get OS information"
                fi
    
                case "$DIST_ID" in
                    RedHat*)
                        OS_NAME="RedHat" ;;
                    debian)
                        OS_NAME="Debian" ;;
                    *)
                        OS_NAME="${DIST_ID}" ;;
                esac
                ;;
            *)
                die "Unsupported OS family: $OS"
                ;;
        esac
    
        echo "${OS}"
        echo "${OS_NAME}"
        echo "${OS_VERSION}"
        echo "${OS_CODENAME}"
    }

    This script returns OS information such as type, name, codename and version. It supports the following Linux distributions: Ubuntu, Debian, CentOS, RedHat. If you want to add support for other distributions, write in the comments below.