mirror of
				https://github.com/keylase/nvidia-patch.git
				synced 2025-11-02 21:51:55 +00:00 
			
		
		
		
	Merge pull request #682 from reloxx13/add_gh_action
Add github action for windows patches
This commit is contained in:
		
							
								
								
									
										15
									
								
								.github/workflows/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								.github/workflows/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
# GitHub Actions usage
 | 
			
		||||
 | 
			
		||||
To create patches to a new driver version simply create a new release with the following name schema:
 | 
			
		||||
- For DCH: `win-dch-536.67`
 | 
			
		||||
- For Studio: `win-studio-536.67`
 | 
			
		||||
- If you need to rerun append `-{try}` e.g. `win-dch-536.67-2`
 | 
			
		||||
 | 
			
		||||
Tagname same as release name.
 | 
			
		||||
 | 
			
		||||
If the patch file exist for a version, they will get deleted and recreated.   
 | 
			
		||||
 | 
			
		||||
The patches will be added as asset to the release.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
> Currently only for windows10 patches
 | 
			
		||||
							
								
								
									
										104
									
								
								.github/workflows/gen_win_patches.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								.github/workflows/gen_win_patches.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
name: Generate Windows patches
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  release:
 | 
			
		||||
    types:
 | 
			
		||||
      - created
 | 
			
		||||
 | 
			
		||||
permissions:
 | 
			
		||||
  contents: write
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  build:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    env:
 | 
			
		||||
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check release name and OS
 | 
			
		||||
        id: check_release
 | 
			
		||||
        run: |
 | 
			
		||||
          release_name="${{ github.event.release.tag_name }}"
 | 
			
		||||
          echo "Release Name: $release_name"
 | 
			
		||||
          if [[ $release_name =~ (win)-(dch|studio)-([0-9]+\.[0-9]+(-[a-zA-Z]+)?)(-.+)? ]]; then
 | 
			
		||||
            os="${BASH_REMATCH[1]}"
 | 
			
		||||
            variant="${BASH_REMATCH[2]}"
 | 
			
		||||
            version="${BASH_REMATCH[3]}"
 | 
			
		||||
            echo "Operating System: $os"
 | 
			
		||||
            echo "Variant: $variant"
 | 
			
		||||
            echo "Version: $version"
 | 
			
		||||
 | 
			
		||||
            if [ "$os" != "win" ]; then
 | 
			
		||||
              echo "Not a Windows release. Stopping the CI workflow."
 | 
			
		||||
              exit 0
 | 
			
		||||
            fi
 | 
			
		||||
 | 
			
		||||
            if [ "$variant" == "dch" ]; then
 | 
			
		||||
              variant="DCH"
 | 
			
		||||
            fi
 | 
			
		||||
 | 
			
		||||
            echo "OS=$os" >> $GITHUB_ENV
 | 
			
		||||
            echo "VARIANT=$variant" >> $GITHUB_ENV
 | 
			
		||||
            echo "VERSION=$version" >> $GITHUB_ENV
 | 
			
		||||
          else
 | 
			
		||||
            echo "Invalid release name format. Must be in the format 'win-dch-123.45' or 'win-studio-123.45'"
 | 
			
		||||
            exit 1
 | 
			
		||||
          fi
 | 
			
		||||
 | 
			
		||||
      - name: Checkout repository
 | 
			
		||||
        uses: actions/checkout@v3
 | 
			
		||||
        with:
 | 
			
		||||
          ref: master
 | 
			
		||||
 | 
			
		||||
      - name: Set up Python
 | 
			
		||||
        uses: actions/setup-python@v4
 | 
			
		||||
        with:
 | 
			
		||||
          python-version: '3.10'
 | 
			
		||||
 | 
			
		||||
      - name: Delete Existing Files
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "Deleting existing files if they exist"
 | 
			
		||||
          rm -f "${{ github.workspace }}/win/win10_x64/${{ env.VERSION }}/nvencodeapi64.1337"
 | 
			
		||||
          rm -f "${{ github.workspace }}/win/win10_x64/${{ env.VERSION }}/nvencodeapi.1337"
 | 
			
		||||
          echo "Existing files deleted successfully"
 | 
			
		||||
 | 
			
		||||
      - name: Run autopatch.py
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "Running autopatch.py with version ${{ env.VERSION }}"
 | 
			
		||||
          cd "${{ github.workspace }}/win/tools/autopatch"
 | 
			
		||||
          python autopatch.py ${{ env.VERSION }}
 | 
			
		||||
          echo "autopatch.py executed successfully"
 | 
			
		||||
 | 
			
		||||
      - name: Run add_driver.py
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "Running add_driver.py with variant ${{ env.VARIANT }} and version ${{ env.VERSION }}"
 | 
			
		||||
          cd "${{ github.workspace }}/tools/readme-autogen"
 | 
			
		||||
          python add_driver.py -W -P GeForce --variant ${{ env.VARIANT }} -w win10 ${{ env.VERSION }}
 | 
			
		||||
          echo "add_driver.py executed successfully"
 | 
			
		||||
 | 
			
		||||
      - name: Run readme_autogen.py
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "Running readme_autogen.py"
 | 
			
		||||
          cd "${{ github.workspace }}/tools/readme-autogen"
 | 
			
		||||
          python readme_autogen.py
 | 
			
		||||
          echo "readme_autogen.py executed successfully"
 | 
			
		||||
 | 
			
		||||
      - name: Commit and push changes
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "Committing and pushing changes"
 | 
			
		||||
          cd "${{ github.workspace }}"
 | 
			
		||||
          git config --local user.email "action@github.com"
 | 
			
		||||
          git config --local user.name "GitHub Action"
 | 
			
		||||
          git add -A
 | 
			
		||||
          git diff --quiet --exit-code --cached || git commit -m "${{ env.OS }}: add support for ${{ env.VARIANT }} driver ${{ env.VERSION }}"
 | 
			
		||||
          git push origin master
 | 
			
		||||
          echo "Committed and pushed changes"
 | 
			
		||||
 | 
			
		||||
      - name: Upload Patch Files
 | 
			
		||||
        uses: softprops/action-gh-release@v1
 | 
			
		||||
        with:
 | 
			
		||||
          files: |
 | 
			
		||||
            ${{ github.workspace }}/win/win10_x64/${{ env.VERSION }}/nvencodeapi64.1337
 | 
			
		||||
            ${{ github.workspace }}/win/win10_x64/${{ env.VERSION }}/nvencodeapi.1337
 | 
			
		||||
        env:
 | 
			
		||||
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
          TAG_NAME: ${{ github.event.release.tag_name }}
 | 
			
		||||
							
								
								
									
										1
									
								
								win/tools/autopatch/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								win/tools/autopatch/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -111,5 +111,4 @@ venv.bak/
 | 
			
		||||
# dont commit 7zip files 7z.dll 7z.exe
 | 
			
		||||
7z.*
 | 
			
		||||
 | 
			
		||||
temp/*
 | 
			
		||||
!.gitempty
 | 
			
		||||
@@ -1,16 +1,15 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
import argparse
 | 
			
		||||
import sys
 | 
			
		||||
import subprocess
 | 
			
		||||
import tempfile
 | 
			
		||||
import os.path
 | 
			
		||||
from binascii import unhexlify
 | 
			
		||||
import xml.etree.ElementTree as ET
 | 
			
		||||
import itertools
 | 
			
		||||
import functools
 | 
			
		||||
import itertools
 | 
			
		||||
import os.path
 | 
			
		||||
import subprocess
 | 
			
		||||
import sys
 | 
			
		||||
import tempfile
 | 
			
		||||
import urllib.request
 | 
			
		||||
 | 
			
		||||
import xml.etree.ElementTree as ET
 | 
			
		||||
from binascii import unhexlify
 | 
			
		||||
 | 
			
		||||
CRLF = b"\x0d\x0a"
 | 
			
		||||
HEADER_FORMAT = b">%s"
 | 
			
		||||
@@ -19,7 +18,6 @@ OFFSET_ADJUSTMENT = 0xC00  # shift specific to x64dbg .1337 format
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def parse_args():
 | 
			
		||||
 | 
			
		||||
    parser = argparse.ArgumentParser(
 | 
			
		||||
        description="Generates .1337 patch for Nvidia drivers for Windows",
 | 
			
		||||
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
 | 
			
		||||
@@ -44,7 +42,7 @@ def parse_args():
 | 
			
		||||
                            "nvencodeapi.dll",
 | 
			
		||||
                        ],
 | 
			
		||||
                        help="name(s) of installed target file. Used for patch "
 | 
			
		||||
                        "header")
 | 
			
		||||
                             "header")
 | 
			
		||||
    parser.add_argument("-P", "--patch-name",
 | 
			
		||||
                        nargs="+",
 | 
			
		||||
                        default=[
 | 
			
		||||
@@ -72,7 +70,7 @@ def parse_args():
 | 
			
		||||
    parser.add_argument("-D", "--direct",
 | 
			
		||||
                        action="store_true",
 | 
			
		||||
                        help="supply patched library directly instead of "
 | 
			
		||||
                        "installer file")
 | 
			
		||||
                             "installer file")
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
    return args
 | 
			
		||||
 | 
			
		||||
@@ -84,9 +82,11 @@ class ExtractException(Exception):
 | 
			
		||||
class PatternNotFoundException(Exception):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MultipleOccurencesException(Exception):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UnknownPlatformException(Exception):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
@@ -145,26 +145,26 @@ def make_patch(archive, *,
 | 
			
		||||
               arch_tgt,
 | 
			
		||||
               search,
 | 
			
		||||
               replacement,
 | 
			
		||||
               tmpdir,
 | 
			
		||||
               sevenzip="7z",
 | 
			
		||||
               direct=False):
 | 
			
		||||
    if direct:
 | 
			
		||||
        with open(archive, 'rb') as fo:
 | 
			
		||||
            f = fo.read()
 | 
			
		||||
    else:
 | 
			
		||||
        with tempfile.TemporaryDirectory() as tmpdir:
 | 
			
		||||
            with ExtractedTarget(archive,
 | 
			
		||||
                                 tmpdir,
 | 
			
		||||
                                 arch_tgt,
 | 
			
		||||
                                 sevenzip=sevenzip) as tgt:
 | 
			
		||||
                if tgt.endswith(".dll"):
 | 
			
		||||
                    with open(tgt, 'rb') as fo:
 | 
			
		||||
                        f = fo.read()
 | 
			
		||||
                else:
 | 
			
		||||
                    f = expand(tgt, sevenzip=sevenzip)
 | 
			
		||||
        with ExtractedTarget(archive,
 | 
			
		||||
                             tmpdir,
 | 
			
		||||
                             arch_tgt,
 | 
			
		||||
                             sevenzip=sevenzip) as tgt:
 | 
			
		||||
            if tgt.endswith(".dll"):
 | 
			
		||||
                with open(tgt, 'rb') as fo:
 | 
			
		||||
                    f = fo.read()
 | 
			
		||||
            else:
 | 
			
		||||
                f = expand(tgt, sevenzip=sevenzip)
 | 
			
		||||
    offset = f.find(search)
 | 
			
		||||
    if offset == -1:
 | 
			
		||||
        raise PatternNotFoundException("Pattern not found.")
 | 
			
		||||
    if f[offset+len(search):].find(search) != -1:
 | 
			
		||||
    if f[offset + len(search):].find(search) != -1:
 | 
			
		||||
        raise MultipleOccurencesException("Multiple occurences of pattern found!")
 | 
			
		||||
    del f
 | 
			
		||||
    print("Pattern found @ %016X" % (offset,), file=sys.stderr)
 | 
			
		||||
@@ -181,7 +181,7 @@ def identify_driver(archive, *, sevenzip="7z"):
 | 
			
		||||
    manifest = extract_single_file(archive, "setup.cfg", sevenzip=sevenzip)
 | 
			
		||||
    root = ET.fromstring(manifest)
 | 
			
		||||
    version = root.attrib['version']
 | 
			
		||||
    product_type = root.find('./properties/string[@name="ProductType"]')\
 | 
			
		||||
    product_type = root.find('./properties/string[@name="ProductType"]') \
 | 
			
		||||
        .attrib['value']
 | 
			
		||||
    return version, product_type
 | 
			
		||||
 | 
			
		||||
@@ -192,92 +192,109 @@ def format_patch(diff, filename):
 | 
			
		||||
        res += LINE_FORMAT % (offset + OFFSET_ADJUSTMENT, left, right)
 | 
			
		||||
    return res
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def patch_flow(installer_file, search, replacement, target, target_name, patch_name, *,
 | 
			
		||||
               direct=False, stdout=False, sevenzip="7z"):
 | 
			
		||||
               tempdir, direct=False, stdout=False, sevenzip="7z"):
 | 
			
		||||
    search = unhexlify(search)
 | 
			
		||||
    replacement = unhexlify(replacement)
 | 
			
		||||
    assert len(search) == len(replacement), "len() of search and replacement"\
 | 
			
		||||
        " is not equal"
 | 
			
		||||
    assert len(search) == len(replacement), "len() of search and replacement is not equal"
 | 
			
		||||
 | 
			
		||||
    # check if installer file exists or try to download
 | 
			
		||||
    if not os.path.isfile(installer_file):  #installer file does not exists, get url for download
 | 
			
		||||
        if not installer_file.startswith("http"):  #installer_file is a version, parse to url
 | 
			
		||||
            filename = installer_file+"-desktop-win10-win11-64bit-international-dch-whql.exe"
 | 
			
		||||
            installer_file = "https://international.download.nvidia.com/Windows/"+installer_file+"/"+filename
 | 
			
		||||
        else:  # installer_file is an url
 | 
			
		||||
            filename = os.path.basename(installer_file)
 | 
			
		||||
        # download installer and save in .temp
 | 
			
		||||
    # Check if installer file exists or try to download
 | 
			
		||||
 | 
			
		||||
        if not os.path.isfile(os.path.join('temp', filename)):  # check if file already downloaded
 | 
			
		||||
            print(f"Downloading... ( {installer_file} TO {os.path.join('temp', filename)} )")
 | 
			
		||||
            print("This may take a while (~800MB)")
 | 
			
		||||
            urllib.request.urlretrieve(installer_file, os.path.join('temp', filename))
 | 
			
		||||
            installer_file = os.path.join('temp', filename)
 | 
			
		||||
    print(f"Search for installer file `{installer_file}`...")
 | 
			
		||||
    if not os.path.isfile(installer_file):
 | 
			
		||||
        print("Installer file is not a file...")
 | 
			
		||||
        if not installer_file.startswith("http"):
 | 
			
		||||
            print("Installer file is not a URL...")
 | 
			
		||||
 | 
			
		||||
            # Construct URL from version
 | 
			
		||||
            print("Installer file is a version!")
 | 
			
		||||
            filename = installer_file + "-desktop-win10-win11-64bit-international-dch-whql.exe"
 | 
			
		||||
            installer_url = f"https://international.download.nvidia.com/Windows/{installer_file}/{filename}"
 | 
			
		||||
        else:
 | 
			
		||||
            installer_file = os.path.join('temp', filename)
 | 
			
		||||
            print(f"Use downloaded file in `{installer_file}`")
 | 
			
		||||
            print("Installer file is a URL!")
 | 
			
		||||
            installer_url = installer_file
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    patch = make_patch(installer_file,
 | 
			
		||||
                       arch_tgt=target,
 | 
			
		||||
                       search=search,
 | 
			
		||||
                       replacement=replacement,
 | 
			
		||||
                       sevenzip=sevenzip,
 | 
			
		||||
                       direct=direct)
 | 
			
		||||
    patch_content = format_patch(patch, target_name)
 | 
			
		||||
    if stdout:
 | 
			
		||||
        with open(sys.stdout.fileno(), mode='wb', closefd=False) as out:
 | 
			
		||||
            out.write(patch_content)
 | 
			
		||||
    elif direct:
 | 
			
		||||
        with open(patch_name, mode='wb') as out:
 | 
			
		||||
            out.write(patch_content)
 | 
			
		||||
    else:
 | 
			
		||||
        version, product_type = identify_driver(installer_file,
 | 
			
		||||
                                                sevenzip=sevenzip)
 | 
			
		||||
        drv_prefix = {
 | 
			
		||||
            "100": "quadro_",
 | 
			
		||||
            "103": "quadro_",
 | 
			
		||||
            "300": "",
 | 
			
		||||
            "301": "nsd_",
 | 
			
		||||
            "303": "", # DCH
 | 
			
		||||
            "304": "nsd_",
 | 
			
		||||
        }
 | 
			
		||||
        installer_name = os.path.basename(installer_file).lower()
 | 
			
		||||
        if 'winserv2008' in installer_name:
 | 
			
		||||
            os_prefix = 'ws2012_x64'
 | 
			
		||||
        elif 'winserv-2012' in installer_name:
 | 
			
		||||
            os_prefix = 'ws2012_x64'
 | 
			
		||||
        elif 'winserv-2016' in installer_name:
 | 
			
		||||
            os_prefix = 'ws2016_x64'
 | 
			
		||||
        elif 'win10' in installer_name:
 | 
			
		||||
            os_prefix = 'win10_x64'
 | 
			
		||||
        elif 'win7' in installer_name:
 | 
			
		||||
            os_prefix = 'win7_x64'
 | 
			
		||||
        if installer_url:
 | 
			
		||||
            try:
 | 
			
		||||
                file_path = os.path.join(tempdir, os.path.basename(installer_url))
 | 
			
		||||
                if not os.path.isfile(file_path):
 | 
			
		||||
                    with urllib.request.urlopen(installer_url) as response, open(file_path, 'wb') as out_file:
 | 
			
		||||
                        print(f"Downloading... ({installer_url} TO {file_path})")
 | 
			
		||||
                        print("This may take a while (~800MB)")
 | 
			
		||||
                        out_file.write(response.read())
 | 
			
		||||
                        print("Download completed successfully!")
 | 
			
		||||
                        installer_file = file_path
 | 
			
		||||
                else:
 | 
			
		||||
                    print(f"Using downloaded file in '{file_path}'")
 | 
			
		||||
                    installer_file = file_path
 | 
			
		||||
            except (urllib.error.URLError, Exception) as e:
 | 
			
		||||
                print(f"Failed to download the file: {e}")
 | 
			
		||||
                return
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
                print(f"An error occurred during download: {str(e)}")
 | 
			
		||||
                return
 | 
			
		||||
        else:
 | 
			
		||||
            raise UnknownPlatformException("Can't infer platform from filename %s"
 | 
			
		||||
                                           % (repr(installer_name),))
 | 
			
		||||
        driver_name = drv_prefix[product_type] + version
 | 
			
		||||
        out_dir = os.path.join(
 | 
			
		||||
            os.path.dirname(
 | 
			
		||||
                os.path.abspath(__file__)), '..', '..', os_prefix, driver_name)
 | 
			
		||||
        os.makedirs(out_dir, 0o755, True)
 | 
			
		||||
        out_filename = os.path.join(out_dir,
 | 
			
		||||
            patch_name)
 | 
			
		||||
        with open(out_filename, 'xb') as out:
 | 
			
		||||
            out.write(patch_content)
 | 
			
		||||
            print(f"Invalid installer file or version: {installer_file}")
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        # Rest of the code remains the same...
 | 
			
		||||
        patch = make_patch(installer_file,
 | 
			
		||||
                           arch_tgt=target,
 | 
			
		||||
                           search=search,
 | 
			
		||||
                           replacement=replacement,
 | 
			
		||||
                           tmpdir=tempdir,
 | 
			
		||||
                           sevenzip=sevenzip,
 | 
			
		||||
                           direct=direct)
 | 
			
		||||
        patch_content = format_patch(patch, target_name)
 | 
			
		||||
 | 
			
		||||
        if stdout:
 | 
			
		||||
            sys.stdout.buffer.write(patch_content)
 | 
			
		||||
        elif direct:
 | 
			
		||||
            with open(patch_name, mode='wb') as out:
 | 
			
		||||
                out.write(patch_content)
 | 
			
		||||
        else:
 | 
			
		||||
            version, product_type = identify_driver(installer_file, sevenzip=sevenzip)
 | 
			
		||||
            drv_prefix = {
 | 
			
		||||
                "100": "quadro_",
 | 
			
		||||
                "103": "quadro_",
 | 
			
		||||
                "300": "",
 | 
			
		||||
                "301": "nsd_",
 | 
			
		||||
                "303": "",  # DCH
 | 
			
		||||
                "304": "nsd_",
 | 
			
		||||
            }
 | 
			
		||||
            installer_name = os.path.basename(installer_file).lower()
 | 
			
		||||
            if 'winserv2008' in installer_name or 'winserv-2012' in installer_name:
 | 
			
		||||
                os_prefix = 'ws2012_x64'
 | 
			
		||||
            elif 'winserv-2016' in installer_name or 'win10' in installer_name:
 | 
			
		||||
                os_prefix = 'win10_x64'
 | 
			
		||||
            elif 'win7' in installer_name:
 | 
			
		||||
                os_prefix = 'win7_x64'
 | 
			
		||||
            else:
 | 
			
		||||
                raise UnknownPlatformException(f"Can't infer platform from filename {installer_name}")
 | 
			
		||||
 | 
			
		||||
            driver_name = drv_prefix.get(product_type, "") + version
 | 
			
		||||
            out_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', os_prefix, driver_name)
 | 
			
		||||
            os.makedirs(out_dir, 0o755, exist_ok=True)
 | 
			
		||||
            out_filename = os.path.join(out_dir, patch_name)
 | 
			
		||||
            with open(out_filename, 'wb') as out:
 | 
			
		||||
                out.write(patch_content)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    args = parse_args()
 | 
			
		||||
 | 
			
		||||
    if args.direct:
 | 
			
		||||
        combinations = zip(args.installer_file, args.search, args.replacement,
 | 
			
		||||
                           args.target, args.target_name, args.patch_name)
 | 
			
		||||
    else:
 | 
			
		||||
        base_params = zip(args.search, args.replacement, args.target, args.target_name, args.patch_name)
 | 
			
		||||
        combinations = ((l,) + r for l, r in itertools.product(args.installer_file, base_params))
 | 
			
		||||
    for params in combinations:
 | 
			
		||||
        patch_flow(*params, direct=args.direct, stdout=args.stdout)
 | 
			
		||||
 | 
			
		||||
    with tempfile.TemporaryDirectory() as tempdir:
 | 
			
		||||
        print(f"Using tempdir `{tempdir}`")
 | 
			
		||||
        for params in combinations:
 | 
			
		||||
            patch_flow(*params, tempdir=tempdir, direct=args.direct, stdout=args.stdout)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user