Blame deploy.py

1a5a38
#!/usr/bin/python3
1a5a38
# -*- coding: utf-8 -*-
1a5a38
# Author: KaratekHD <karatekhd@opensuse.org>
1a5a38
#
1a5a38
# Copyright (c) 2021 KaratekHD.
1a5a38
# is program is free software; you can redistribute it and/or modify
1a5a38
# it under the terms of the GNU General Public License as published by
1a5a38
# the Free Software Foundation; either version 3 of the License, or
1a5a38
# (at your option) any later version.
1a5a38
#
1a5a38
# This program is distributed in the hope that it will be useful,
1a5a38
# but WITHOUT ANY WARRANTY; without even the implied warranty of
1a5a38
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1a5a38
# GNU General Public License for more details.
1a5a38
#
1a5a38
# You should have received a copy of the GNU General Public License along
1a5a38
# with this program; if not, see <http://www.gnu.org/licenses/>.
1a5a38
#
1a5a38
1a5a38
import argparse
1a5a38
import os
1a5a38
import sys
1a5a38
import tarfile
1a5a38
1a5a38
from termcolor import colored
1a5a38
1a5a38
parser = argparse.ArgumentParser(
1a5a38
    description="Deploy openSUSE Tumbleweed to the Mars MA3.")
1a5a38
parser.add_argument("-r", "--rootfs", help="Path to rottfs.tar", required=True)
1a5a38
parser.add_argument(
1a5a38
    "-d",
1a5a38
    "--device",
1a5a38
    help="Deviceprefix to deploy to (e.g. /dev/mmcblk0p)",
1a5a38
    required=True)
1a5a38
parser.add_argument(
1a5a38
    "-i",
1a5a38
    "--input_dir",
1a5a38
    help="Build files generated by build.sh",
1a5a38
    required=True)
1a5a38
args = parser.parse_args()
1a5a38
rootfs_path = args.rootfs
1a5a38
block = args.device
1a5a38
1a5a38
1a5a38
# Check if script is run as root
1a5a38
if os.geteuid() != 0:
1a5a38
    print(colored("Script must be run as root, relaunching...", "cyan"))
1a5a38
    # Relaunch script as root
1a5a38
    # Get all args to one string
1a5a38
    os.system("sudo python3 " + " ".join(sys.argv))
1a5a38
    # Exit script
1a5a38
    sys.exit(1)
1a5a38
1a5a38
# Check if args.input-dir is a directory
1a5a38
if not os.path.isdir(args.input_dir):
1a5a38
    print(colored("Input directory is invalid!", "red"))
1a5a38
    sys.exit(1)
1a5a38
os.chdir(args.input_dir)
1a5a38
# Check if block device exists
1a5a38
if not os.path.exists(block):
1a5a38
    print(colored("Block device does not exist", "red"))
1a5a38
    sys.exit(1)
1a5a38
1a5a38
# Check if something is mounted on /mnt abort if so
1a5a38
if os.path.ismount("/mnt"):
1a5a38
    print(colored("Please unmount /mnt before running this script", "red"))
1a5a38
    sys.exit(1)
1a5a38
1a5a38
# Check if /mnt/boot exists and create if not
1a5a38
if not os.path.exists("/mnt/boot"):
1a5a38
    os.makedirs("/mnt/boot")
1a5a38
# Check if /mnt/rootfs exists and create if not
1a5a38
if not os.path.exists("/mnt/rootfs"):
1a5a38
    os.makedirs("/mnt/rootfs")
1a5a38
1a5a38
# Umount all partitions
1a5a38
# Check if /mnt/rootfs is mounted
1a5a38
if os.path.ismount("/mnt/rootfs"):
1a5a38
    print(colored("Unmounting /mnt/rootfs", "yellow"))
1a5a38
    os.system("umount -l /mnt/rootfs")
1a5a38
# Check if /mnt/boot is mounted
1a5a38
if os.path.ismount("/mnt/boot"):
1a5a38
    print(colored("Unmounting /mnt/boot"))
1a5a38
    os.system("umount -l /mnt/boot")
1a5a38
1a5a38
# TODO: Partitioning of the SD card
1a5a38
1a5a38
# Format the SD card
1a5a38
print(colored("Formatting partition 1 with fat32...", "yellow"))
1a5a38
os.system("mkfs.vfat -F 32 -n BOOT {}1".format(block))
1a5a38
print(colored("Formatted partition 1", "green"))
1a5a38
print(colored("Formatting partition 3 with ext2...", "yellow"))
1a5a38
os.system("mkfs.ext2 -L rootfs {}3".format(block))
1a5a38
print(colored("Formatted partition 3", "green"))
1a5a38
1a5a38
# Flash preloader
1a5a38
print(colored("Flashing preloader...", "yellow"))
1a5a38
os.system("dd if=preloader-mkpimage.bin of={}2 status=progress".format(block))
1a5a38
print(colored("Preloader flashed!", "green"))
1a5a38
print(colored("Syncing...", "yellow"))
1a5a38
os.system("sync")
1a5a38
print(colored("Synced!", "green"))
1a5a38
1a5a38
# Check if device is mounted
1a5a38
if not os.path.ismount("/mnt/rootfs"):
1a5a38
    print(colored("Mounting /mnt/rootfs", "yellow"))
1a5a38
    os.system("sudo mount {}3 /mnt/rootfs".format(block))
1a5a38
if not os.path.ismount("/mnt/boot"):
1a5a38
    print(colored("Mounting /mnt/boot", "yellow"))
1a5a38
    os.system("sudo mount {}1 /mnt/boot".format(block))
1a5a38
1a5a38
print(colored("Copying files to /mnt/boot", "yellow"))
1a5a38
1a5a38
# List of files to copy
1a5a38
files = ["uImage", "devicetree.dtb", "fpga.rbf", "u-boot.img", "uboot.scr"]
1a5a38
1a5a38
# Copy files to /mnt/boot with progress bar
1a5a38
for file in files:
1a5a38
    print(colored("- " + file, "green"))
1a5a38
    with open(file, "rb") as f:
1a5a38
        with open("/mnt/boot/" + file, "wb") as f2:
1a5a38
            while True:
1a5a38
                data = f.read(1024)
1a5a38
                if not data:
1a5a38
                    break
1a5a38
                f2.write(data)
1a5a38
1a5a38
# Remove everything from /mnt/rootfs
1a5a38
print(colored("Removing everything from /mnt/rootfs...", "yellow"))
1a5a38
os.system("rm -rf /mnt/rootfs/*")
1a5a38
1a5a38
# Extract rootfs from tarfile to /mnt/rootfs
1a5a38
# Check wether tarfile is .gz or .xz
1a5a38
compression = ""
1a5a38
if rootfs_path.endswith(".gz") or rootfs_path.endswith(".xz"):
1a5a38
    if rootfs_path.endswith(".gz"):
1a5a38
        compression = "gz"
1a5a38
    elif rootfs_path.endswith(".xz"):
1a5a38
        compression = "xz"
1a5a38
    print(
1a5a38
        colored(
1a5a38
            "Extracting rootfs from {} to /mnt/rootfs...".format(rootfs_path),
1a5a38
            "yellow"))
1a5a38
    with tarfile.open(rootfs_path, "r:" + compression) as tar:
1a5a38
        tar.extractall("/mnt/rootfs")
1a5a38
    print(colored("Extracted {} to /mnt/rootfs".format(rootfs_path), "green"))
1a5a38
else:
1a5a38
    # Extract .tar
1a5a38
    print(colored("Extracting {} to /mnt/rootfs...".format(rootfs_path), "yellow"))
1a5a38
    with tarfile.open(rootfs_path) as tar:
1a5a38
        tar.extractall("/mnt/rootfs")
1a5a38
    print(colored("Extracted {} to /mnt/rootfs".format(rootfs_path), "green"))
1a5a38
print(colored("Syncing...", "yellow"))
1a5a38
os.system("sync")
1a5a38
print(colored("Umounting devices...", "yellow"))
1a5a38
os.system("umount /mnt/boot")
1a5a38
os.system("umount /mnt/rootfs")
1a5a38
1a5a38
print(colored("Done", "green"))