Exemple #1
0
def test_human_readable_size():
    assert human_readable_size(512) == "512.0B"
    assert human_readable_size(512 * KiB) == "512.0KiB"
    assert human_readable_size(512 * MiB) == "512.0MiB"
    assert human_readable_size(512 * GiB) == "512.0GiB"
    assert human_readable_size(512 * TiB) == "512.0TiB"
    assert human_readable_size(512 * PiB) == "512.0PiB"
    assert human_readable_size(512 * EiB) == "512.0EiB"
    assert human_readable_size(512 * ZiB) == "512.0ZiB"
    assert human_readable_size(512 * YiB) == "512.0YiB"
    assert human_readable_size(51200 * YiB) == "51200.0YiB"
Exemple #2
0
 def update_folder(self):
     '''更新文件浏览窗口'''
     ls_file = "ls.txt"
     reply = self.client.ls(local_file=ls_file) #获取当前文件夹下的所有文件信息
     if reply == True:
         self.folderWidget.clearContents()
         self.folderWidget.setRowCount(len(open(ls_file,'r').readlines()))
         i = 0
         with open(ls_file, "r") as f:
             for line in f:
                 list = line.split()
                 #文件名
                 name_item = QTableWidgetItem(list[8])
                 name_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
                 self.folderWidget.setItem(i, 0, name_item)
                 #文件类型
                 type = get_file_type(file_name=list[8], access_string=list[0])
                 type_item = QTableWidgetItem(type)
                 type_item.setFlags(Qt.NoItemFlags)
                 self.folderWidget.setItem(i, 1, type_item)
                 #文件大小
                 if type == "folder":
                     size = "--"
                 else:
                     size = human_readable_size(list[4])
                 size_item = QTableWidgetItem(size)
                 size_item.setFlags(Qt.NoItemFlags)
                 self.folderWidget.setItem(i, 2, size_item)
                 #文件的最近修改时间
                 time_item = QTableWidgetItem(" ".join(list[5:8]))
                 time_item.setFlags(Qt.NoItemFlags)
                 self.folderWidget.setItem(i, 3, time_item)
                 i += 1
Exemple #3
0
    def _set_ram(self, requested_ram):
        """ applies requested RAM to qemu if it's available otherwise less """

        # less than a GB is very short
        if host_ram / ONE_GiB <= 1.0:
            self._ram = "256m"
            return

        # at most, use RAM minus 512m
        max_ram = int(host_ram - ONE_GiB / 2)

        # parse specified ram in Mega or Giga
        if re.match(r"\d+[mg]$", requested_ram):
            ram_amount, ram_unit = int(requested_ram[:-1]), requested_ram[-1]
        else:
            # no unit, assuming M
            ram_amount, ram_unit = int(requested_ram), "m"
        if ram_unit == "g":
            ram_amount = ram_amount * (ONE_GiB)

        # use requested if it doesn't exceed max_ram
        ram = max_ram if ram_amount > max_ram else ram_amount

        # vexpress-a15 is capped at 30G
        if int(ram / ONE_GiB) > 30:
            ram = 30 * ONE_GiB

        self._ram = "{ram}M".format(ram=int(ram / ONE_MiB))
        self._logger.std(
            " using {ram} RAM".format(ram=human_readable_size(ram)))
    def get_iterator():
        devices = []
        plist = plistlib.loads(subprocess.check_output(["diskutil", "list", "-plist"]))

        device_names = []
        for name in plist["AllDisks"]:
            device_names.extend(re.findall(r"^(disk\d+)$", name))

        for name in device_names:
            plist = plistlib.loads(subprocess.check_output(["diskutil", "info", "-plist", name]))
            size = plist["Size"]
            formatted_size = human_readable_size(size)
            devices.append({
                "bus_protocol": plist["BusProtocol"],
                "device_identifier": plist["DeviceIdentifier"],
                "device": plist["DeviceNode"],
                "io_registry_entry_name": plist["IORegistryEntryName"],
                "media_name": plist["MediaName"],
                "media_type": plist["MediaType"],
                "removable": plist["Removable"],
                "size": size,
                "formatted_size": formatted_size,
                "volume_name": plist["VolumeName"],
                })

        return filter(lambda d: d["removable"] and d["size"] != 0 and d["bus_protocol"] != "Disk Image", devices)
    def get_iterator():
        devices = []
        bus = dbus.SystemBus()
        udisk = bus.get_object('org.freedesktop.UDisks2', '/org/freedesktop/UDisks2')
        udisk_interface = dbus.Interface(udisk, 'org.freedesktop.DBus.ObjectManager')

        for key, value in udisk_interface.GetManagedObjects().items():
            info = value.get('org.freedesktop.UDisks2.Block', {})
            if info.get('IdUsage') == "" and info.get('Drive') != "/":
                device = bytes(info.get('PreferredDevice')).decode('utf-8')

                size = info.get('Size')
                formatted_size = human_readable_size(size)
                devices.append({
                        "key": key,
                        # Because device name ends with \x00
                        "device": device.replace("\x00", ""),
                        "size": size,
                        "formatted_size": formatted_size,
                        "id_label": info.get('IdLabel'),
                        "drive_key": info.get('Drive'),
                        "id": info.get('Id'),
                        })


        for drive_key, drive_value in udisk_interface.GetManagedObjects().items():
            info = drive_value.get('org.freedesktop.UDisks2.Drive', {})
            for block in devices:
                if drive_key == block["drive_key"]:
                    block["drive_removable"] = info.get('Removable')
                    block["drive_id"] = info.get('Id')
                    block["drive_connection_bus"] = info.get('ConnectionBus')

        return filter(lambda d: d["drive_removable"] and d["size"] != 0, devices)
    def get_iterator():
        lines = subprocess.check_output(["wmic", "diskdrive"], **startup_info_args()).decode('utf-8').splitlines()

        column = {}
        matches = re.finditer(r"(\w+\W+)", lines[0])
        for match in matches:
            column[lines[0][match.start():match.end()].strip()] = match

        devices = []
        lines.pop(0)
        for line in filter(lambda l: len(l) is not 0, lines):
            size = extract_field(column["Size"], line)
            formatted_size = human_readable_size(size)
            devices.append({
                "caption": extract_field(column["Caption"], line),
                "description": extract_field(column["Description"], line),
                "device": extract_field(column["DeviceID"], line),
                "media_type": extract_field(column["MediaType"], line),
                "model": extract_field(column["Model"], line),
                "name": extract_field(column["Name"], line),
                "size": size,
                "formatted_size": formatted_size,
                })

        return filter(lambda d: d["media_type"] != "Fixed hard disk media" and d["size"] is not '', devices)
Exemple #7
0
def list_cache_files(logger, build_folder, cache_folder, **kwargs):
    """ colored list of all files in cache with legend (to Keep or to Remove) """

    logger.step("Listing cache content for: {}".format(cache_folder))

    cfiles = get_analyzed_cache_files(logger, cache_folder)
    cache_size, nb_files, free_space = get_cache_size_and_free_space(
        build_folder, cache_folder
    )
    logger.std("-------------\nLEGEND\n-------------")
    logger.std("K: to be kept (latest content or alien folder)")
    logger.std("R: to be removed (obsolete, damaged or alien file)")
    logger.std("F: is a file")
    logger.std("D: is a directory")
    logger.std("-------------")
    claimable = 0
    for cfile in cfiles:
        if cfile["latest"]:
            fmt = logger.succ
        elif not cfile["alien"]:
            fmt = logger.err
            claimable += cfile["size"]
        else:
            fmt = logger.std

        fmt(
            " {a} [{s}]\t\t{t} {f}{sf}".format(
                a="K" if cfile["keep"] else "R",
                s=human_readable_size(cfile["size"]),
                f=cfile["fname"],
                t="D" if cfile["isdir"] else "F",
                sf="  --- [{}]".format(cfile["latest"]) if cfile["latest"] else "",
            )
        )

    logger.std("-------------")
    logger.std("TOTAL USED SPACE in cache: {}".format(human_readable_size(cache_size)))
    logger.std("TOTAL FREE SPACE in cache: {}".format(human_readable_size(free_space)))
    logger.std(
        "TOTAL CLAIMABLE SPACE in cache: {}".format(human_readable_size(claimable))
    )
    return 0
    def scan_files(self, paths):
        if self.use_tqdm:
            paths = tqdm(paths, unit="files")

        for file_path in paths:
            with open(file_path, "rb") as f:
                data = f.read()
            self.scan_buf(data)

            if self.use_tqdm:
                paths.set_postfix(
                    {'waste': util.human_readable_size(self.total_waste)})
Exemple #9
0
def display_cache_and_free_space(
    logger, build_folder, cache_folder, old_cache_size=None, old_free_space=None
):
    """ display cache size and free space shortcut """
    cache_size, nb_files, free_space = get_cache_size_and_free_space(
        build_folder, cache_folder
    )

    if old_cache_size:
        logger.std(
            "NEW CACHE SIZE: {} (removed {})".format(
                human_readable_size(cache_size),
                human_readable_size(old_cache_size - cache_size),
            )
        )
    else:
        logger.std(
            "CACHE SIZE: {} ({} files)".format(
                human_readable_size(cache_size), nb_files
            )
        )

    if old_free_space:
        logger.std(
            "NEW FREE SPACE: {} (reclaimed {})".format(
                human_readable_size(free_space),
                human_readable_size(free_space - old_free_space),
            )
        )
    else:
        logger.std("FREE SPACE: {}".format(human_readable_size(free_space)))

    return cache_size, free_space
Exemple #10
0
 def update_free_space(self):
     free_space = self.get_free_space()
     human_readable_free_space = human_readable_size(free_space)
     self.component.free_space_label1.set_text(human_readable_free_space)
     self.component.free_space_label2.set_text(human_readable_free_space)
     condition = free_space >= 0
     validate_label(self.component.free_space_label1, condition)
     validate_label(self.component.free_space_label2, condition)
     for row in self.component.zim_list_store:
         if free_space - int(row[9]) >= 0:
             row[11] = VALID_RGBA
         else:
             row[11] = INVALID_RGBA
     return free_space
Exemple #11
0
def run_in_qemu(image_fpath, disk_size, root_size, logger, cancel_event,
                qemu_ram):

    logger.step("starting QEMU")
    try:
        # Instance emulator
        emulator = qemu.Emulator(
            data.vexpress_boot_kernel,
            data.vexpress_boot_dtb,
            image_fpath,
            logger,
            ram=qemu_ram,
            is_master=True,
        )

        logger.step("resizing QEMU image to {}GB".format(
            human_readable_size(disk_size, False)))
        emulator.resize_image(disk_size)

        # Run emulation
        with emulator.run(cancel_event) as emulation:
            # enable SSH for good
            logger.step("Enable SSH")
            emulation.exec_cmd("sudo /bin/systemctl enable ssh")

            logger.step("Copy ansiblecube")
            ansible_root_path = os.path.dirname(ansiblecube_emulation_path)
            emulation.exec_cmd(
                "sudo mkdir --mode 0755 -p {}".format(ansible_root_path))
            emulation.put_dir(data.ansiblecube_path,
                              ansiblecube_emulation_path)
            emulation.exec_cmd(
                "sudo chown pi:pi -R {}".format(ansible_root_path))

            # Run ansiblecube
            logger.step("Run ansiblecube")
            run_for_image(machine=emulation,
                          root_partition_size=root_size,
                          disk_size=disk_size)

    except Exception as e:
        return e

    return None
    def get_iterator():
        devices = []
        bus = dbus.SystemBus()
        udisk = bus.get_object("org.freedesktop.UDisks2",
                               "/org/freedesktop/UDisks2")
        udisk_interface = dbus.Interface(udisk,
                                         "org.freedesktop.DBus.ObjectManager")

        for key, value in udisk_interface.GetManagedObjects().items():
            info = value.get("org.freedesktop.UDisks2.Block", {})
            if info.get("IdUsage") == "" and info.get("Drive") != "/":
                device = bytes(info.get("PreferredDevice")).decode("utf-8")

                size = info.get("Size")
                formatted_size = human_readable_size(size, binary=False)
                devices.append({
                    "key": key,
                    # Because device name ends with \x00
                    "device": device.replace("\x00", ""),
                    "size": size,
                    "formatted_size": formatted_size,
                    "id_label": info.get("IdLabel"),
                    "drive_key": info.get("Drive"),
                    "id": info.get("Id"),
                })

        for drive_key, drive_value in udisk_interface.GetManagedObjects(
        ).items():
            info = drive_value.get("org.freedesktop.UDisks2.Drive", {})
            for block in devices:
                if drive_key == block["drive_key"]:
                    block["drive_removable"] = info.get("Removable")
                    block["drive_id"] = info.get("Id")
                    block["drive_connection_bus"] = info.get("ConnectionBus")

        return filter(lambda d: d["drive_removable"] and d["size"] != 0,
                      devices)
Exemple #13
0
def test():
    logger = logging.LoggerAdapter(logging.getLogger(), {"caller": __name__})

    src_image_folder = "test/images/*.png"
    src_images = []

    for src_img in glob.glob(src_image_folder):
        src_images.append(src_img)

    payloads_folder = "test/payloads/*.test"
    payloads = []

    for payload in glob.glob(payloads_folder):
        payloads.append(payload)

    tmp_payload_output_path = "test/test_payload_extracted"
    tmp_output_image = "test/test_processed_image.png"

    test_methods = ["LSB", "PVD"]

    logger.info("Beginning StegArmory test!")

    total_iterations = len(src_images) * len(payloads) * len(test_methods)

    logger.info("Running %d test cases!" % total_iterations)

    results = []

    i = 0

    for src_img in src_images:
        for payload in payloads:
            for method in test_methods:
                src_img_filename = os.path.basename(src_img)
                payload_filename = os.path.basename(payload)
                tmp_output_img_filename = os.path.basename(tmp_output_image)

                logger.info("Testing %s embed on image %s with payload %s" %
                            (method, src_img_filename, payload_filename))

                if method == "LSB":
                    proc = processor.LSBProcessor(src_img)
                elif method == "PVD":
                    proc = processor.PVDProcessor(src_img)

                embed_time_a = time.perf_counter()
                proc.embed_payload(payload, tmp_output_image)
                embed_time_b = time.perf_counter()
                embed_time = round(embed_time_b - embed_time_a, 4)

                logger.info(
                    "Testing %s extract on image %s with payload %s" %
                    (method, tmp_output_img_filename, payload_filename))
                proc2 = type(proc)(tmp_output_image)

                extract_time_a = time.perf_counter()
                proc2.extract_payload(tmp_payload_output_path)
                extract_time_b = time.perf_counter()
                extract_time = round(extract_time_b - extract_time_a, 4)

                proc.compare(proc2)

                results.append([
                    src_img, method, payload, embed_time, extract_time,
                    util.human_readable_size(proc.max_payload_size // 8,
                                             2), proc.comparison_stats['psnr'],
                    proc.comparison_stats['ssim']
                ])
                i += 1

                logger.info("Overall Progress: %d/%d (%s%%)" %
                            (i, total_iterations,
                             str(round((i / total_iterations) * 100, 2))))

    print(
        tabulate.tabulate(results,
                          headers=[
                              "Source Image", "Method", "Payload",
                              "Embed Time", "Extract Time", "Max Payload Size",
                              "PSNR", "SSIM"
                          ]))
Exemple #14
0
def run_installation(
    name,
    timezone,
    language,
    wifi_pwd,
    admin_account,
    kalite,
    aflatoun,
    wikifundi,
    edupi,
    edupi_resources,
    nomad,
    mathews,
    africatik,
    zim_install,
    size,
    logger,
    cancel_event,
    sd_card,
    favicon,
    logo,
    css,
    done_callback=None,
    build_dir=".",
    filename=None,
    qemu_ram="2G",
    shrink=False,
):

    logger.start(bool(sd_card))

    logger.stage("init")
    cache_folder = get_cache(build_dir)

    try:
        logger.std("Preventing system from sleeping")
        sleep_ref = prevent_sleep(logger)

        logger.step("Check System Requirements")
        logger.std("Please read {} for details".format(requirements_url))
        sysreq_ok, missing_deps = host_matches_requirements(build_dir)
        if not sysreq_ok:
            raise SystemError(
                "Your system does not matches system requirements:\n{}".format(
                    "\n".join([" - {}".format(dep) for dep in missing_deps])))

        logger.step("Ensure user files are present")
        for user_fpath in (edupi_resources, favicon, logo, css):
            if (user_fpath is not None and not isremote(user_fpath)
                    and not os.path.exists(user_fpath)):
                raise ValueError(
                    "Specified file is not available ({})".format(user_fpath))

        logger.step("Prepare Image file")

        # set image names
        if not filename:
            filename = "hotspot-{}".format(
                datetime.today().strftime("%Y_%m_%d-%H_%M_%S"))

        image_final_path = os.path.join(build_dir, filename + ".img")
        image_building_path = os.path.join(build_dir,
                                           filename + ".BUILDING.img")
        image_error_path = os.path.join(build_dir, filename + ".ERROR.img")

        # loop device mode on linux (for mkfs in userspace)
        if sys.platform == "linux":
            loop_dev = guess_next_loop_device(logger)
            if loop_dev and not can_write_on(loop_dev):
                logger.step("Change loop device mode ({})".format(sd_card))
                previous_loop_mode = allow_write_on(loop_dev, logger)
            else:
                previous_loop_mode = None

        base_image = get_content("hotspot_master_image")
        # harmonize options
        packages = [] if zim_install is None else zim_install
        kalite_languages = [] if kalite is None else kalite
        wikifundi_languages = [] if wikifundi is None else wikifundi
        aflatoun_languages = ["fr", "en"] if aflatoun else []

        if edupi_resources and not isremote(edupi_resources):
            logger.step("Copying EduPi resources into cache")
            shutil.copy(edupi_resources, cache_folder)

        # prepare ansible options
        ansible_options = {
            "name": name,
            "timezone": timezone,
            "language": language,
            "language_name": dict(data.hotspot_languages)[language],
            "edupi": edupi,
            "edupi_resources": edupi_resources,
            "nomad": nomad,
            "mathews": mathews,
            "africatik": africatik,
            "wikifundi_languages": wikifundi_languages,
            "aflatoun_languages": aflatoun_languages,
            "kalite_languages": kalite_languages,
            "packages": packages,
            "wifi_pwd": wifi_pwd,
            "admin_account": admin_account,
            "disk_size": size,
            "root_partition_size": base_image.get("root_partition_size"),
        }
        extra_vars, secret_keys = ansiblecube.build_extra_vars(
            **ansible_options)

        # display config in log
        logger.step("Dumping Hotspot Configuration")
        logger.raw_std(
            json.dumps(
                {
                    k: "****" if k in secret_keys else v
                    for k, v in extra_vars.items()
                },
                indent=4,
            ))

        # gen homepage HTML
        homepage_path = save_homepage(
            generate_homepage(logger, ansible_options))
        logger.std("homepage saved to: {}".format(homepage_path))

        # Download Base image
        logger.stage("master")
        logger.step("Retrieving base image file")

        rf = download_content(base_image, logger, build_dir)
        if not rf.successful:
            logger.err(
                "Failed to download base image.\n{e}".format(e=rf.exception))
            sys.exit(1)
        elif rf.found:
            logger.std("Reusing already downloaded base image ZIP file")
        logger.progress(0.5)

        # extract base image and rename
        logger.step("Extracting base image from ZIP file")
        unzip_file(
            archive_fpath=rf.fpath,
            src_fname=base_image["name"].replace(".zip", ""),
            build_folder=build_dir,
            dest_fpath=image_building_path,
        )
        logger.std("Extraction complete: {p}".format(p=image_building_path))
        logger.progress(0.9)

        if not os.path.exists(image_building_path):
            raise IOError(
                "image path does not exists: {}".format(image_building_path))

        logger.step("Testing mount procedure")
        if not test_mount_procedure(image_building_path, logger, True):
            raise ValueError("thorough mount procedure failed")

        # collection contains both downloads and processing callbacks
        # for all requested contents
        collection = get_collection(
            edupi=edupi,
            edupi_resources=edupi_resources,
            nomad=nomad,
            mathews=mathews,
            africatik=africatik,
            packages=packages,
            kalite_languages=kalite_languages,
            wikifundi_languages=wikifundi_languages,
            aflatoun_languages=aflatoun_languages,
        )

        # download contents into cache
        logger.stage("download")
        logger.step("Starting all content downloads")
        downloads = list(get_all_contents_for(collection))
        archives_total_size = sum([c["archive_size"] for c in downloads])
        retrieved = 0

        for dl_content in downloads:
            logger.step("Retrieving {name} ({size})".format(
                name=dl_content["name"],
                size=human_readable_size(dl_content["archive_size"]),
            ))

            rf = download_content(dl_content, logger, build_dir)
            if not rf.successful:
                logger.err("Error downloading {u} to {p}\n{e}".format(
                    u=dl_content["url"], p=rf.fpath, e=rf.exception))
                raise rf.exception if rf.exception else IOError
            elif rf.found:
                logger.std("Reusing already downloaded {p}".format(p=rf.fpath))
            else:
                logger.std("Saved `{p}` successfuly: {s}".format(
                    p=dl_content["name"],
                    s=human_readable_size(rf.downloaded_size)))
            retrieved += dl_content["archive_size"]
            logger.progress(retrieved, archives_total_size)

        # check edupi resources compliance
        if edupi_resources:
            logger.step("Verifying EduPi resources file names")
            exfat_compat, exfat_errors = ensure_zip_exfat_compatible(
                get_content_cache(get_alien_content(edupi_resources),
                                  cache_folder, True))
            if not exfat_compat:
                raise ValueError("Your EduPi resources archive is incorrect.\n"
                                 "It should be a ZIP file of a root folder "
                                 "in which all files have exfat-compatible "
                                 "names (no {chars})\n... {fnames}".format(
                                     chars=" ".join(EXFAT_FORBIDDEN_CHARS),
                                     fnames="\n... ".join(exfat_errors),
                                 ))
            else:
                logger.std("EduPi resources archive OK")

        # instanciate emulator
        logger.stage("setup")
        logger.step("Preparing qemu VM")
        emulator = qemu.Emulator(
            data.vexpress_boot_kernel,
            data.vexpress_boot_dtb,
            image_building_path,
            logger,
            ram=qemu_ram,
        )

        # Resize image
        logger.step("Resizing image file from {s1} to {s2}".format(
            s1=human_readable_size(emulator.get_image_size()),
            s2=human_readable_size(size),
        ))
        if size < emulator.get_image_size():
            logger.err("cannot decrease image size")
            raise ValueError("cannot decrease image size")

        emulator.resize_image(size)

        # Run emulation
        logger.step("Starting-up VM (first-time)")
        with emulator.run(cancel_event) as emulation:
            # copying ansiblecube again into the VM
            # should the master-version been updated
            logger.step("Copy ansiblecube")
            emulation.exec_cmd("sudo /bin/rm -rf {}".format(
                ansiblecube.ansiblecube_path))
            emulation.put_dir(data.ansiblecube_path,
                              ansiblecube.ansiblecube_path)

            logger.step("Run ansiblecube for `resize`")
            ansiblecube.run(emulation, ["resize"], extra_vars, secret_keys)

        logger.step("Starting-up VM (second-time)")
        with emulator.run(cancel_event) as emulation:

            logger.step("Run ansiblecube phase I")
            ansiblecube.run_phase_one(
                emulation,
                extra_vars,
                secret_keys,
                homepage=homepage_path,
                logo=logo,
                favicon=favicon,
                css=css,
            )

        # wait for QEMU to release file (windows mostly)
        time.sleep(10)

        # mount image's 3rd partition on host
        logger.stage("copy")

        logger.step("Formating data partition on host")
        format_data_partition(image_building_path, logger)

        logger.step("Mounting data partition on host")
        # copy contents from cache to mount point
        try:
            mount_point, device = mount_data_partition(image_building_path,
                                                       logger)
            logger.step("Processing downloaded content onto data partition")
            expanded_total_size = sum([c["expanded_size"] for c in downloads])
            processed = 0

            for category, content_dl_cb, content_run_cb, cb_kwargs in collection:

                logger.step("Processing {cat}".format(cat=category))
                content_run_cb(cache_folder=cache_folder,
                               mount_point=mount_point,
                               logger=logger,
                               **cb_kwargs)
                # size of expanded files for this category (for progress)
                processed += sum(
                    [c["expanded_size"] for c in content_dl_cb(**cb_kwargs)])
                logger.progress(processed, expanded_total_size)
        except Exception as exp:
            try:
                unmount_data_partition(mount_point, device, logger)
            except NameError:
                pass  # if mount_point or device are not defined
            raise exp

        time.sleep(10)

        # unmount partition
        logger.step("Unmounting data partition")
        unmount_data_partition(mount_point, device, logger)

        time.sleep(10)

        # rerun emulation for discovery
        logger.stage("move")
        logger.step("Starting-up VM (third-time)")
        with emulator.run(cancel_event) as emulation:
            logger.step("Run ansiblecube phase II")
            ansiblecube.run_phase_two(emulation, extra_vars, secret_keys)

        if shrink:
            logger.step("Shrink size of physical image file")
            # calculate physical size of image
            required_image_size = get_required_image_size(collection)
            if required_image_size + ONE_GB >= size:
                # less than 1GB difference, don't bother
                pass
            else:
                # set physical size to required + margin
                physical_size = math.ceil(
                    required_image_size / ONE_GB) * ONE_GB
                emulator.resize_image(physical_size, shrink=True)

        # wait for QEMU to release file (windows mostly)
        logger.succ("Image creation successful.")
        time.sleep(20)

    except Exception as e:
        logger.failed(str(e))

        # display traceback on logger
        logger.std("\n--- Exception Trace ---\n{exp}\n---".format(
            exp=traceback.format_exc()))

        # Set final image filename
        if os.path.isfile(image_building_path):
            os.rename(image_building_path, image_error_path)

        error = e
    else:
        try:
            # Set final image filename
            tries = 0
            while True:
                try:
                    os.rename(image_building_path, image_final_path)
                except Exception as exp:
                    logger.err(exp)
                    tries += 1
                    if tries > 3:
                        raise exp
                    time.sleep(5 * tries)
                    continue
                else:
                    logger.std(
                        "Renamed image file to {}".format(image_final_path))
                    break

            # Write image to SD Card
            if sd_card:
                logger.stage("write")
                logger.step("Writting image to SD-card ({})".format(sd_card))

                try:

                    etcher_writer = EtcherWriterThread(args=(image_final_path,
                                                             sd_card, logger))
                    cancel_event.register_thread(thread=etcher_writer)
                    etcher_writer.start()
                    etcher_writer.join(timeout=2)  # make sure it started
                    while etcher_writer.is_alive():
                        pass
                    logger.std("not alive")
                    etcher_writer.join(timeout=2)
                    cancel_event.unregister_thread()
                    if etcher_writer.exp is not None:
                        raise etcher_writer.exp

                    logger.std("Done writing and verifying.")
                    time.sleep(5)
                except Exception:
                    logger.succ("Image created successfuly.")
                    logger.err(
                        "Writing or verification of Image to your SD-card failed.\n"
                        "Please use a third party tool to flash your image "
                        "onto your SD-card. See File menu for links to Etcher."
                    )
                    raise Exception("Failed to write Image to SD-card")

        except Exception as e:
            logger.failed(str(e))

            # display traceback on logger
            logger.std("\n--- Exception Trace ---\n{exp}\n---".format(
                exp=traceback.format_exc()))
            error = e
        else:
            logger.complete()
            error = None
    finally:
        logger.std("Restoring system sleep policy")
        restore_sleep_policy(sleep_ref, logger)

        if sys.platform == "linux" and loop_dev and previous_loop_mode:
            logger.step("Restoring loop device ({}) mode".format(loop_dev))
            restore_mode(loop_dev, previous_loop_mode, logger)

        # display durations summary
        logger.summary()

    if done_callback:
        done_callback(error)

    return error
Exemple #15
0
    def run_installation_button_clicked(self, button):
        all_valid = True

        project_name = self.component.project_name_entry.get_text()
        allowed_chars = set(string.ascii_uppercase + string.ascii_lowercase +
                            string.digits + '-')
        condition = len(project_name) >= 1 and len(project_name) <= 64 and set(
            project_name) <= allowed_chars
        validate_label(self.component.project_name_label, condition)
        self.component.project_name_constraints_revealer.set_reveal_child(
            not condition)
        all_valid = all_valid and condition

        language_id = self.component.language_combobox.get_active()
        language = data.ideascube_languages[language_id][0]
        condition = language_id != -1
        validate_label(self.component.language_label, condition)
        all_valid = all_valid and condition

        timezone_id = self.component.timezone_combobox.get_active()
        timezone = self.component.timezone_tree_store[timezone_id][0]
        condition = timezone_id != -1
        validate_label(self.component.timezone_label, condition)
        all_valid = all_valid and condition

        if self.component.wifi_password_switch.get_state():
            wifi_pwd = None
            condition = True
        else:
            wifi_pwd = self.component.wifi_password_entry.get_text()
            condition = len(wifi_pwd) <= 31 and set(
                wifi_pwd) <= set(string.ascii_uppercase +
                                 string.ascii_lowercase + string.digits)
        self.component.wifi_password_constraints_revealer.set_reveal_child(
            not condition)
        validate_label(self.component.wifi_password_label, condition)
        all_valid = all_valid and condition

        if not self.component.admin_account_switch.get_state():
            admin_account = None
            login_condition = True
            pwd_condition = True
        else:
            admin_account = {
                "login": self.component.admin_account_login_entry.get_text(),
                "pwd": self.component.admin_account_pwd_entry.get_text(),
            }
            login_condition = len(admin_account["login"]) <= 31 and set(
                admin_account["login"]) <= set(string.ascii_uppercase +
                                               string.ascii_lowercase +
                                               string.digits)
            pwd_condition = len(admin_account["pwd"]) <= 31 and set(
                admin_account["pwd"]) <= set(string.ascii_uppercase +
                                             string.ascii_lowercase +
                                             string.digits)
        self.component.admin_account_login_constraints_revealer.set_reveal_child(
            not login_condition)
        self.component.admin_account_pwd_constraints_revealer.set_reveal_child(
            not pwd_condition)
        validate_label(self.component.admin_account_login_label,
                       login_condition)
        validate_label(self.component.admin_account_pwd_label, pwd_condition)
        all_valid = all_valid and pwd_condition and login_condition

        zim_install = []
        for zim in self.component.zim_list_store:
            if zim[8]:
                zim_install.append(zim[0])

        output_size = self.get_output_size()
        if self.component.output_stack.get_visible_child_name() == "sd_card":
            sd_card_id = self.component.sd_card_combobox.get_active()
            condition = sd_card_id != -1
            validate_label(self.component.sd_card_label, condition)
            all_valid = all_valid and condition

            if sd_card_id == -1:
                sd_card = None
            else:
                device_index = sd_card_info.get_device_index()
                sd_card = self.component.sd_card_list_store[sd_card_id][
                    device_index]
        else:
            sd_card = None
            condition = output_size > 0
            validate_label(self.component.size_label, condition)
            all_valid = all_valid and condition

        condition = self.update_free_space() >= 0
        validate_label(self.component.free_space_name_label, condition)
        all_valid = all_valid and condition

        kalite_active_langs = [
            lang for lang, button in self.iter_kalite_check_button()
            if button.get_active()
        ]
        if len(kalite_active_langs) != 0:
            kalite = kalite_active_langs
        else:
            kalite = None

        wikifundi_active_langs = [
            lang for lang, button in self.iter_wikifundi_check_button()
            if button.get_active()
        ]
        if len(wikifundi_active_langs) != 0:
            wikifundi = wikifundi_active_langs
        else:
            wikifundi = None

        aflatoun = self.component.aflatoun_switch.get_active()

        edupi = self.component.edupi_switch.get_active()

        logo = self.component.logo_chooser.get_filename()
        favicon = self.component.favicon_chooser.get_filename()
        css = self.component.css_chooser.get_filename()

        build_dir = self.component.build_path_chooser.get_filename()
        condition = build_dir != None
        validate_label(self.component.build_path_chooser_label, condition)
        all_valid = all_valid and condition

        # Check if there is enough space in build_dir to build image
        if build_dir != None:
            free_space = get_free_space_in_dir(build_dir)
            remaining_space = free_space - output_size
            if remaining_space < 0:
                self.component.space_error_image_location_label.set_text(
                    build_dir)
                self.component.space_error_total_space_required_label.set_text(
                    human_readable_size(output_size))
                self.component.space_error_space_available_label.set_text(
                    human_readable_size(free_space))
                self.component.space_error_space_missing_label.set_text(
                    human_readable_size(-remaining_space))

                self.component.space_error_window.show()
                all_valid = False

        if all_valid:

            def target():
                run_installation(name=project_name,
                                 timezone=timezone,
                                 language=language,
                                 wifi_pwd=wifi_pwd,
                                 kalite=kalite,
                                 wikifundi=wikifundi,
                                 aflatoun=aflatoun,
                                 edupi=edupi,
                                 zim_install=zim_install,
                                 size=output_size,
                                 logger=self.logger,
                                 cancel_event=self.cancel_event,
                                 sd_card=sd_card,
                                 logo=logo,
                                 favicon=favicon,
                                 css=css,
                                 build_dir=build_dir,
                                 admin_account=admin_account,
                                 done_callback=lambda error: GLib.idle_add(
                                     self.installation_done, error))

            self.component.window.hide()
            self.reset_run_window()
            self.component.run_window.show()
            threading.Thread(target=target, daemon=True).start()
Exemple #16
0
    def __init__(self, catalog):
        self.catalog = catalog

        builder = Gtk.Builder()
        builder.add_from_file(data.ui_glade)

        self.component = Component(builder)
        self.cancel_event = CancelEvent()
        self.logger = Logger(self.component.run_text_view.get_buffer(),
                             self.component.run_step_label)

        # main window
        self.component.window.connect("delete-event", Gtk.main_quit)

        # gtk file filters (macOS fix)
        self.component.favicon_filter.set_name("Favicon (ICO, PNG)")  # opt
        self.component.favicon_filter.add_pattern("*.png")
        self.component.favicon_filter.add_pattern("*.ico")
        self.component.favicon_chooser.add_filter(
            self.component.favicon_filter)

        self.component.logo_filter.set_name("Logo (PNG)")  # opt
        self.component.logo_filter.add_pattern("*.png")
        self.component.logo_chooser.add_filter(self.component.logo_filter)

        self.component.css_filter.set_name("CSS File")  # opt
        self.component.css_filter.add_pattern("*.css")
        self.component.css_chooser.add_filter(self.component.css_filter)

        # menu bar
        self.component.menu_quit.connect(
            "activate", lambda widget: self.component.window.close())
        self.component.menu_about.connect("activate", self.activate_menu_about)

        self.component.menu_load_config.connect("activate",
                                                self.activate_menu_config,
                                                False)
        self.component.menu_save_config.connect("activate",
                                                self.activate_menu_config,
                                                True)

        # wifi password
        self.component.wifi_password_switch.connect(
            "notify::active", lambda switch, state: self.component.
            wifi_password_revealer.set_reveal_child(not switch.get_active()))

        # admin account
        self.component.admin_account_switch.connect(
            "notify::active", lambda switch, state: self.component.
            admin_account_revealer.set_reveal_child(switch.get_active()))

        # ideascube language
        for code, language in data.ideascube_languages:
            self.component.language_tree_store.append([code, language])

        renderer = Gtk.CellRendererText()
        self.component.language_combobox.pack_start(renderer, True)
        self.component.language_combobox.add_attribute(renderer, "text", 1)

        index = -1
        for i, (code, language) in enumerate(data.ideascube_languages):
            if code == 'en':
                index = i
        self.component.language_combobox.set_active(index)

        # timezone
        default_id = -1
        local_tz = tzlocal.get_localzone()
        for id, timezone in enumerate(pytz.common_timezones):
            if timezone == "UTC" and default_id == -1:
                default_id = id
            if pytz.timezone(timezone) == local_tz:
                default_id = id
            self.component.timezone_tree_store.append(None, [timezone])

        renderer = Gtk.CellRendererText()
        self.component.timezone_combobox.pack_start(renderer, True)
        self.component.timezone_combobox.add_attribute(renderer, "text", 0)
        self.component.timezone_combobox.set_active(default_id)

        # output
        self.component.sd_card_combobox.connect(
            "changed", lambda _: self.update_free_space())
        self.component.sd_card_refresh_button.connect(
            "clicked", self.sd_card_refresh_button_clicked)
        self.component.output_stack.connect(
            "notify::visible-child",
            lambda switch, state: self.update_free_space())
        self.component.size_entry.connect("changed",
                                          lambda _: self.update_free_space())

        types = [info["typ"] for info in sd_card_info.informations]
        self.component.sd_card_list_store = Gtk.ListStore(*types)
        self.component.sd_card_combobox.set_model(
            self.component.sd_card_list_store)

        for counter in range(0, sd_card_info.visible_informations):
            cell_renderer = Gtk.CellRendererText()
            self.component.sd_card_combobox.pack_start(cell_renderer, True)
            self.component.sd_card_combobox.add_attribute(
                cell_renderer, "text", counter)

        # about dialog
        self.component.about_dialog.set_logo(
            GdkPixbuf.Pixbuf.new_from_file_at_scale(data.pibox_logo, 200, -1,
                                                    True))

        # done window
        self.component.done_window_ok_button.connect(
            "clicked", lambda widget: self.component.done_window.hide())
        self.component.done_window.connect("delete-event", hide_on_delete)

        # space error window
        self.component.space_error_window_ok_button.connect(
            "clicked", self.space_error_window_ok_button_clicked)
        self.component.space_error_window.connect("delete-event",
                                                  hide_on_delete)

        # run window
        self.component.run_installation_button.connect(
            "clicked", self.run_installation_button_clicked)
        self.component.run_window.connect("delete-event",
                                          self.run_window_delete_event)
        self.component.run_text_view.get_buffer().connect(
            "modified-changed", self.run_text_view_scroll_down)
        self.component.run_quit_button.connect("clicked",
                                               self.run_quit_button_clicked)
        self.component.run_abort_button.connect("clicked",
                                                self.run_abort_button_clicked)
        self.component.run_copy_log_to_clipboard_button.connect(
            "clicked", self.run_copy_log_to_clipboard_button_clicked)
        self.component.run_new_install_button.connect(
            "clicked", self.run_new_install_button_clicked)

        # zim content
        self.component.zim_choose_content_button.connect(
            "clicked", self.zim_choose_content_button_clicked)

        self.component.zim_list_store = Gtk.ListStore(
            str,  # key
            str,  # name
            str,  # url
            str,  # description
            str,  # formatted_size
            object,  # languages
            str,  # type
            str,  # version
            bool,  # selected
            str,  # size
            bool,  # its language is selected
            Gdk.RGBA  # background color
        )
        self.component.zim_list_store.set_sort_column_id(
            1, Gtk.SortType.ASCENDING)

        all_languages = set()

        for one_catalog in catalog:
            for (key, value) in one_catalog["all"].items():
                name = value["name"]
                url = value["url"]
                description = value.get("description") or "none"
                # We double indicated size because in ideascube throught ansiblecube
                # will first download the zip file and then extract the content
                # TODO: an improvment would be to delete zip file after extraction and
                # compute a temporar space needed that is max of all installed size
                size = str(value["size"] * 2)
                languages_iso = (value.get("language")
                                 or "Unkown language").split(",")
                languages = set(
                    map(lambda l: langcodes.Language.get(l).language_name(),
                        languages_iso))
                typ = value["type"]
                version = str(value["version"])
                formatted_size = human_readable_size(int(size))

                self.component.zim_list_store.append([
                    key, name, url, description, formatted_size, languages,
                    typ, version, False, size, True, VALID_RGBA
                ])
                all_languages |= languages

        self.component.zim_language_list_store = Gtk.ListStore(str)
        self.component.zim_language_list_store.set_sort_column_id(
            0, Gtk.SortType.ASCENDING)
        for language in all_languages:
            self.component.zim_language_list_store.append([language])

        # zim window
        self.component.zim_window_done_button.connect(
            "clicked", self.zim_done_button_clicked)
        self.component.zim_window.connect("delete-event", hide_on_delete)
        self.component.zim_tree_view.connect("row-activated",
                                             self.available_zim_clicked)
        self.component.choosen_zim_tree_view.connect("row-activated",
                                                     self.choosen_zim_clicked)

        ## zim window available tree view
        self.component.zim_tree_view.set_model(self.component.zim_list_store)

        renderer_text = Gtk.CellRendererText()
        column_text = Gtk.TreeViewColumn("Name", renderer_text, text=1)
        self.component.zim_tree_view.append_column(column_text)
        column_text = Gtk.TreeViewColumn("Size", renderer_text, text=4)
        self.component.zim_tree_view.append_column(column_text)
        column_text = Gtk.TreeViewColumn("Description", renderer_text, text=3)
        self.component.zim_tree_view.append_column(column_text)
        column_text.add_attribute(renderer_text, "cell_background_rgba", 11)

        zim_filter = self.component.zim_list_store.filter_new()
        zim_filter.set_visible_func(self.zim_filter_func)
        self.component.zim_tree_view.set_model(zim_filter)

        # zim window choosen tree view
        self.component.choosen_zim_tree_view.set_model(
            self.component.zim_list_store)

        renderer_text = Gtk.CellRendererText()
        column_text = Gtk.TreeViewColumn("Name", renderer_text, text=1)
        self.component.choosen_zim_tree_view.append_column(column_text)
        column_text = Gtk.TreeViewColumn("Size", renderer_text, text=4)
        self.component.choosen_zim_tree_view.append_column(column_text)
        column_text = Gtk.TreeViewColumn("Description", renderer_text, text=3)
        self.component.choosen_zim_tree_view.append_column(column_text)

        choosen_zim_filter = self.component.zim_list_store.filter_new()
        choosen_zim_filter.set_visible_func(self.choosen_zim_filter_func)
        self.component.choosen_zim_tree_view.set_model(choosen_zim_filter)

        # kalite
        for lang, button in self.iter_kalite_check_button():
            button.set_label("{} ({})".format(
                button.get_label(),
                human_readable_size(data.kalite_sizes[lang])))
            button.connect("toggled", lambda button: self.update_free_space())

        # wikifundi
        for lang, button in self.iter_wikifundi_check_button():
            button.set_label("{} ({})".format(
                button.get_label(),
                human_readable_size(data.wikifundi_sizes[lang])))
            button.connect("toggled", lambda button: self.update_free_space())

        # aflatoun
        self.component.aflatoun_switch.connect(
            "notify::active", lambda switch, state: self.update_free_space())
        self.component.aflatoun_label.set_label("{} ({})".format(
            self.component.aflatoun_label.get_label(),
            human_readable_size(data.aflatoun_size)))

        # edupi
        self.component.edupi_switch.connect(
            "notify::active", lambda switch, state: self.update_free_space())
        self.component.edupi_label.set_label("{} ({})".format(
            self.component.edupi_label.get_label(),
            human_readable_size(data.edupi_size)))

        # language tree view
        renderer_text = Gtk.CellRendererText()
        column_text = Gtk.TreeViewColumn("Language", renderer_text, text=0)
        self.component.zim_language_tree_view.append_column(column_text)

        self.component.zim_language_tree_view.get_selection().set_mode(
            Gtk.SelectionMode(3))
        self.component.zim_language_tree_view.set_model(
            self.component.zim_language_list_store)
        self.component.zim_language_tree_view.get_selection().select_all()
        self.component.zim_language_tree_view.get_selection().connect(
            "changed", self.zim_language_selection_changed)

        self.refresh_disk_list()
        self.update_free_space()

        self.component.window.show()
Exemple #17
0
def main(logger,
         disk_size,
         root_size,
         build_folder,
         qemu_ram,
         image_fname=None):

    # convert sizes to bytes and make sure those are usable
    try:
        root_size = int(root_size) * ONE_GB
        disk_size = get_adjusted_image_size(int(disk_size) * ONE_GB)

        if root_size < MIN_ROOT_SIZE:
            raise ValueError("root partition must be at least {}".format(
                human_readable_size(MIN_ROOT_SIZE, False)))

        if root_size >= disk_size:
            raise ValueError("root partition must be smaller than disk size")
    except Exception as exp:
        logger.err("Erroneous size option: {}".format(exp))
        sys.exit(1)

    logger.step("Starting master creation: {} ({} root)".format(
        human_readable_size(disk_size, False),
        human_readable_size(root_size, False)))

    # default output file name
    if image_fname is None:
        image_fname = "hotspot-master_{date}.img".format(
            date=datetime.datetime.now().strftime("%Y-%m-%d"))
    image_fpath = os.path.join(build_folder, image_fname)

    logger.step("starting with target: {}".format(image_fpath))

    # download raspbian
    logger.step("Retrieving raspbian image file")
    raspbian_image = get_content("raspbian_image")
    rf = download_content(raspbian_image, logger, build_folder)
    if not rf.successful:
        logger.err("Failed to download raspbian.\n{e}".format(e=rf.exception))
        sys.exit(1)
    elif rf.found:
        logger.std("Reusing already downloaded raspbian ZIP file")

    # extract raspbian and rename
    logger.step("Extracting raspbian image from ZIP file")
    unzip_file(
        archive_fpath=rf.fpath,
        src_fname=raspbian_image["name"].replace(".zip", ".img"),
        build_folder=build_folder,
        dest_fpath=image_fpath,
    )
    logger.std("Extraction complete: {p}".format(p=image_fpath))

    if not os.path.exists(image_fpath):
        raise IOError("image path does not exists: {}".format(image_fpath))

    error = run_in_qemu(image_fpath, disk_size, root_size, logger,
                        CancelEvent(), qemu_ram)

    if error:
        logger.err("ERROR: unable to properly create image: {}".format(error))
        sys.exit(1)

    logger.std("SUCCESS! {} was built successfuly".format(image_fpath))
        file_size = len(buf)
        jpeg_size = jpegparser.read_jpeg(buf)['size']
        wasted_size = file_size - jpeg_size

        self.total_data += file_size
        self.total_jpeg += jpeg_size
        self.total_waste += wasted_size


args = parse_args()

scanner = JpegScanner()

try:
    from tqdm import tqdm
except ImportError:
    scanner.use_tqdm = False

if args.subcommand == 'dir':
    scanner.scan_dir(args.dir)
elif args.subcommand == 'files':
    scanner.scan_files(args.paths)

print()

print("total:   %s" % (util.human_readable_size(scanner.total_data)))
print("real:    %s (%.2f%%)" % (util.human_readable_size(
    scanner.total_jpeg), scanner.total_jpeg / scanner.total_data * 100))
print("garbage: %s (%.2f%%)" % (util.human_readable_size(
    scanner.total_waste), scanner.total_waste / scanner.total_data * 100))
Exemple #19
0
        "login": args.admin_account[0],
        "pwd": args.admin_account[1]
    }
else:
    admin_account = {"login": "******", "pwd": "admin-password"}

# parse requested size
try:
    args.size = humanfriendly.parse_size(args.size)
    args.output_size = get_adjusted_image_size(
        args.size)  # adjust image size for HW
except Exception:
    print("Unable to understand required size ({})".format(args.size))
    sys.exit(1)
else:
    args.human_size = human_readable_size(args.output_size, False)

# check arguments
(
    valid_project_name,
    valid_language,
    valid_timezone,
    valid_wifi_pwd,
    valid_admin_login,
    valid_admin_pwd,
) = check_user_inputs(
    project_name=args.name,
    language=args.language,
    timezone=args.timezone,
    wifi_pwd=args.wifi_pwd,
    admin_login=admin_account["login"],