diff options
author | Alyssa Ross <hi@alyssa.is> | 2021-04-28 14:39:00 +0000 |
---|---|---|
committer | Alyssa Ross <hi@alyssa.is> | 2021-06-10 08:52:36 +0000 |
commit | 693e64ef7421374338ddb1dc12b9573feec75972 (patch) | |
tree | 2526ac075d248699c35d63e04499890ee4381f5f /nixpkgs/nixos/lib | |
parent | 7014df2256694d97093d6f2bb1db340d346dea88 (diff) | |
parent | 8e4fe32876ca15e3d5eb3ecd3ca0b224417f5f17 (diff) | |
download | nixlib-693e64ef7421374338ddb1dc12b9573feec75972.tar nixlib-693e64ef7421374338ddb1dc12b9573feec75972.tar.gz nixlib-693e64ef7421374338ddb1dc12b9573feec75972.tar.bz2 nixlib-693e64ef7421374338ddb1dc12b9573feec75972.tar.lz nixlib-693e64ef7421374338ddb1dc12b9573feec75972.tar.xz nixlib-693e64ef7421374338ddb1dc12b9573feec75972.tar.zst nixlib-693e64ef7421374338ddb1dc12b9573feec75972.zip |
Merge commit '8e4fe32876ca15e3d5eb3ecd3ca0b224417f5f17'
Diffstat (limited to 'nixpkgs/nixos/lib')
-rw-r--r-- | nixpkgs/nixos/lib/make-disk-image.nix | 78 | ||||
-rw-r--r-- | nixpkgs/nixos/lib/make-options-doc/default.nix | 26 | ||||
-rw-r--r-- | nixpkgs/nixos/lib/test-driver/test-driver.py | 79 |
3 files changed, 146 insertions, 37 deletions
diff --git a/nixpkgs/nixos/lib/make-disk-image.nix b/nixpkgs/nixos/lib/make-disk-image.nix index 023d0791a5c7..7d40d3b5548e 100644 --- a/nixpkgs/nixos/lib/make-disk-image.nix +++ b/nixpkgs/nixos/lib/make-disk-image.nix @@ -15,6 +15,8 @@ , # size of the boot partition, is only used if partitionTableType is # either "efi" or "hybrid" + # This will be undersized slightly, as this is actually the offset of + # the end of the partition. Generally it will be 1MiB smaller. bootSize ? "256M" , # The files and directories to be placed in the target file system. @@ -163,6 +165,8 @@ let format' = format; in let closureInfo = pkgs.closureInfo { rootPaths = [ config.system.build.toplevel channelSources ]; }; + blockSize = toString (4 * 1024); # ext4fs block size (not block device sector size) + prepareImage = '' export PATH=${binPath} @@ -175,6 +179,24 @@ let format' = format; in let echo $(( "$1" * 512 )) } + # Given lines of numbers, adds them together + sum_lines() { + local acc=0 + while read -r number; do + acc=$((acc+number)) + done + echo "$acc" + } + + mebibyte=$(( 1024 * 1024 )) + + # Approximative percentage of reserved space in an ext4 fs over 512MiB. + # 0.05208587646484375 + # × 1000, integer part: 52 + compute_fudge() { + echo $(( $1 * 52 / 1000 )) + } + mkdir $out root="$PWD/root" @@ -235,12 +257,53 @@ let format' = format; in let ${if diskSize == "auto" then '' ${if partitionTableType == "efi" || partitionTableType == "hybrid" then '' - additionalSpace=$(( ($(numfmt --from=iec '${additionalSpace}') + $(numfmt --from=iec '${bootSize}')) / 1000 )) + # Add the GPT at the end + gptSpace=$(( 512 * 34 * 1 )) + # Normally we'd need to account for alignment and things, if bootSize + # represented the actual size of the boot partition. But it instead + # represents the offset at which it ends. + # So we know bootSize is the reserved space in front of the partition. + reservedSpace=$(( gptSpace + $(numfmt --from=iec '${bootSize}') )) + '' else if partitionTableType == "legacy+gpt" then '' + # Add the GPT at the end + gptSpace=$(( 512 * 34 * 1 )) + # And include the bios_grub partition; the ext4 partition starts at 2MB exactly. + reservedSpace=$(( gptSpace + 2 * mebibyte )) + '' else if partitionTableType == "legacy" then '' + # Add the 1MiB aligned reserved space (includes MBR) + reservedSpace=$(( mebibyte )) '' else '' - additionalSpace=$(( $(numfmt --from=iec '${additionalSpace}') / 1000 )) + reservedSpace=0 ''} - diskSize=$(( $(set -- $(du -d0 $root); echo "$1") + $additionalSpace )) - truncate -s "$diskSize"K $diskImage + additionalSpace=$(( $(numfmt --from=iec '${additionalSpace}') + reservedSpace )) + + # Compute required space in filesystem blocks + diskUsage=$(find . ! -type d -exec 'du' '--apparent-size' '--block-size' "${blockSize}" '{}' ';' | cut -f1 | sum_lines) + # Each inode takes space! + numInodes=$(find . | wc -l) + # Convert to bytes, inodes take two blocks each! + diskUsage=$(( (diskUsage + 2 * numInodes) * ${blockSize} )) + # Then increase the required space to account for the reserved blocks. + fudge=$(compute_fudge $diskUsage) + requiredFilesystemSpace=$(( diskUsage + fudge )) + + diskSize=$(( requiredFilesystemSpace + additionalSpace )) + + # Round up to the nearest mebibyte. + # This ensures whole 512 bytes sector sizes in the disk image + # and helps towards aligning partitions optimally. + if (( diskSize % mebibyte )); then + diskSize=$(( ( diskSize / mebibyte + 1) * mebibyte )) + fi + + truncate -s "$diskSize" $diskImage + + printf "Automatic disk size...\n" + printf " Closure space use: %d bytes\n" $diskUsage + printf " fudge: %d bytes\n" $fudge + printf " Filesystem size needed: %d bytes\n" $requiredFilesystemSpace + printf " Additional space: %d bytes\n" $additionalSpace + printf " Disk image size: %d bytes\n" $diskSize '' else '' truncate -s ${toString diskSize}M $diskImage ''} @@ -251,9 +314,9 @@ let format' = format; in let # Get start & length of the root partition in sectors to $START and $SECTORS. eval $(partx $diskImage -o START,SECTORS --nr ${rootPartition} --pairs) - mkfs.${fsType} -F -L ${label} $diskImage -E offset=$(sectorsToBytes $START) $(sectorsToKilobytes $SECTORS)K + mkfs.${fsType} -b ${blockSize} -F -L ${label} $diskImage -E offset=$(sectorsToBytes $START) $(sectorsToKilobytes $SECTORS)K '' else '' - mkfs.${fsType} -F -L ${label} $diskImage + mkfs.${fsType} -b ${blockSize} -F -L ${label} $diskImage ''} echo "copying staging root to image..." @@ -283,6 +346,9 @@ in pkgs.vmTools.runInLinuxVM ( # Some tools assume these exist ln -s vda /dev/xvda ln -s vda /dev/sda + # make systemd-boot find ESP without udev + mkdir /dev/block + ln -s /dev/vda1 /dev/block/254:1 mountPoint=/mnt mkdir $mountPoint diff --git a/nixpkgs/nixos/lib/make-options-doc/default.nix b/nixpkgs/nixos/lib/make-options-doc/default.nix index a1161621f0d4..14015ab64abb 100644 --- a/nixpkgs/nixos/lib/make-options-doc/default.nix +++ b/nixpkgs/nixos/lib/make-options-doc/default.nix @@ -126,11 +126,37 @@ let } ''; + singleMDDoc = name: value: '' + ## ${lib.escape [ "<" ">" ] name} + ${value.description} + + ${lib.optionalString (value ? type) '' + *_Type_*: + ${value.type} + ''} + + ${lib.optionalString (value ? default) '' + *_Default_* + ``` + ${builtins.toJSON value.default} + ``` + ''} + + ${lib.optionalString (value ? example) '' + *_Example_* + ``` + ${builtins.toJSON value.example} + ``` + ''} + ''; + in { inherit optionsNix; optionsAsciiDoc = lib.concatStringsSep "\n" (lib.mapAttrsToList singleAsciiDoc optionsNix); + optionsMDDoc = lib.concatStringsSep "\n" (lib.mapAttrsToList singleMDDoc optionsNix); + optionsJSON = pkgs.runCommand "options.json" { meta.description = "List of NixOS options in JSON format"; buildInputs = [ pkgs.brotli ]; diff --git a/nixpkgs/nixos/lib/test-driver/test-driver.py b/nixpkgs/nixos/lib/test-driver/test-driver.py index 96b75a49928f..7800a49e4107 100644 --- a/nixpkgs/nixos/lib/test-driver/test-driver.py +++ b/nixpkgs/nixos/lib/test-driver/test-driver.py @@ -1,7 +1,7 @@ #! /somewhere/python3 from contextlib import contextmanager, _GeneratorContextManager from queue import Queue, Empty -from typing import Tuple, Any, Callable, Dict, Iterator, Optional, List +from typing import Tuple, Any, Callable, Dict, Iterator, Optional, List, Iterable from xml.sax.saxutils import XMLGenerator import queue import io @@ -205,6 +205,37 @@ class Logger: self.xml.endElement("nest") +def _perform_ocr_on_screenshot( + screenshot_path: str, model_ids: Iterable[int] +) -> List[str]: + if shutil.which("tesseract") is None: + raise Exception("OCR requested but enableOCR is false") + + magick_args = ( + "-filter Catrom -density 72 -resample 300 " + + "-contrast -normalize -despeckle -type grayscale " + + "-sharpen 1 -posterize 3 -negate -gamma 100 " + + "-blur 1x65535" + ) + + tess_args = f"-c debug_file=/dev/null --psm 11" + + cmd = f"convert {magick_args} {screenshot_path} tiff:{screenshot_path}.tiff" + ret = subprocess.run(cmd, shell=True, capture_output=True) + if ret.returncode != 0: + raise Exception(f"TIFF conversion failed with exit code {ret.returncode}") + + model_results = [] + for model_id in model_ids: + cmd = f"tesseract {screenshot_path}.tiff - {tess_args} --oem {model_id}" + ret = subprocess.run(cmd, shell=True, capture_output=True) + if ret.returncode != 0: + raise Exception(f"OCR failed with exit code {ret.returncode}") + model_results.append(ret.stdout.decode("utf-8")) + + return model_results + + class Machine: def __init__(self, args: Dict[str, Any]) -> None: if "name" in args: @@ -637,43 +668,29 @@ class Machine: """Debugging: Dump the contents of the TTY<n>""" self.execute("fold -w 80 /dev/vcs{} | systemd-cat".format(tty)) - def get_screen_text(self) -> str: - if shutil.which("tesseract") is None: - raise Exception("get_screen_text used but enableOCR is false") - - magick_args = ( - "-filter Catrom -density 72 -resample 300 " - + "-contrast -normalize -despeckle -type grayscale " - + "-sharpen 1 -posterize 3 -negate -gamma 100 " - + "-blur 1x65535" - ) - - tess_args = "-c debug_file=/dev/null --psm 11 --oem 2" + def _get_screen_text_variants(self, model_ids: Iterable[int]) -> List[str]: + with tempfile.TemporaryDirectory() as tmpdir: + screenshot_path = os.path.join(tmpdir, "ppm") + self.send_monitor_command(f"screendump {screenshot_path}") + return _perform_ocr_on_screenshot(screenshot_path, model_ids) - with self.nested("performing optical character recognition"): - with tempfile.NamedTemporaryFile() as tmpin: - self.send_monitor_command("screendump {}".format(tmpin.name)) - - cmd = "convert {} {} tiff:- | tesseract - - {}".format( - magick_args, tmpin.name, tess_args - ) - ret = subprocess.run(cmd, shell=True, capture_output=True) - if ret.returncode != 0: - raise Exception( - "OCR failed with exit code {}".format(ret.returncode) - ) + def get_screen_text_variants(self) -> List[str]: + return self._get_screen_text_variants([0, 1, 2]) - return ret.stdout.decode("utf-8") + def get_screen_text(self) -> str: + return self._get_screen_text_variants([2])[0] def wait_for_text(self, regex: str) -> None: def screen_matches(last: bool) -> bool: - text = self.get_screen_text() - matches = re.search(regex, text) is not None + variants = self.get_screen_text_variants() + for text in variants: + if re.search(regex, text) is not None: + return True - if last and not matches: - self.log("Last OCR attempt failed. Text was: {}".format(text)) + if last: + self.log("Last OCR attempt failed. Text was: {}".format(variants)) - return matches + return False with self.nested("waiting for {} to appear on screen".format(regex)): retry(screen_matches) |