|
| 1 | +FROM nixos/nix:2.18.8 |
| 2 | + |
| 3 | +# default build args |
| 4 | +ARG MAX_JOBS=4 |
| 5 | +ARG CORES=4 |
| 6 | + |
| 7 | +# Combine RUN commands to reduce layers and improve caching |
| 8 | +RUN echo "experimental-features = nix-command flakes" >> /etc/nix/nix.conf \ |
| 9 | + && echo "max-jobs = $MAX_JOBS" >> /etc/nix/nix.conf \ |
| 10 | + && echo "cores = $CORES" >> /etc/nix/nix.conf \ |
| 11 | + && nix profile install nixpkgs#cachix nixpkgs#git-lfs \ |
| 12 | + && cachix use huggingface |
| 13 | +WORKDIR /app |
| 14 | +# Copy builder files |
| 15 | +COPY . /etc/kernel-builder/ |
| 16 | +# Set environment variables |
| 17 | +ENV MAX_JOBS=${MAX_JOBS} |
| 18 | +ENV CORES=${CORES} |
| 19 | +# Create directory and setup script |
| 20 | +RUN mkdir -p /etc/kernel-builder && \ |
| 21 | + cat <<'EOF' > /etc/kernel-builder/cli.sh |
| 22 | +#!/bin/sh |
| 23 | +set -e |
| 24 | +# Default values |
| 25 | +BUILD_URL="" |
| 26 | +DEV_SHELL=0 |
| 27 | +HELP=0 |
| 28 | +# CLI usage function |
| 29 | +function show_usage { |
| 30 | + echo "Kernel Builder CLI" |
| 31 | + echo "" |
| 32 | + echo "Usage: docker run [docker-options] kernel-builder:dev [command] [options]" |
| 33 | + echo "" |
| 34 | + echo "Commands:" |
| 35 | + echo " build Build the kernel extension (default if no command specified)" |
| 36 | + echo " dev Start a development shell" |
| 37 | + echo " fetch [URL] Clone and build from a Git URL" |
| 38 | + echo " help Show this help message" |
| 39 | + echo "" |
| 40 | + echo "Options:" |
| 41 | + echo " --jobs, -j NUMBER Set maximum number of parallel jobs (default: $MAX_JOBS)" |
| 42 | + echo " --cores, -c NUMBER Set number of cores per job (default: $CORES)" |
| 43 | + echo "" |
| 44 | + echo "Examples:" |
| 45 | + echo " docker run --mount type=bind,source=$(pwd),target=/kernelcode kernel-builder:root build" |
| 46 | + echo " docker run -it --mount type=bind,source=$(pwd),target=/kernelcode kernel-builder:root dev" |
| 47 | + echo " docker run --mount type=bind,source=$(pwd),target=/kernelcode kernel-builder:root fetch https://huggingface.co/user/repo.git" |
| 48 | +} |
| 49 | + |
| 50 | +# Function to generate a basic flake.nix if it doesn't exist |
| 51 | +function ensure_flake_exists { |
| 52 | + local work_dir=$1 |
| 53 | + if [ ! -f "${work_dir}/flake.nix" ]; then |
| 54 | + echo "No flake.nix found, creating a basic one..." |
| 55 | + cat <<'FLAKE_EOF' > "${work_dir}/flake.nix" |
| 56 | +{ |
| 57 | + description = "Flake for Torch kernel extension"; |
| 58 | + inputs = { |
| 59 | + kernel-builder.url = "github:huggingface/kernel-builder"; |
| 60 | + }; |
| 61 | + outputs = { self, kernel-builder, }: |
| 62 | + kernel-builder.lib.genFlakeOutputs { |
| 63 | + path = ./.; |
| 64 | + rev = self.shortRev or self.dirtyShortRev or self.lastModifiedDate; |
| 65 | + }; |
| 66 | +} |
| 67 | +FLAKE_EOF |
| 68 | + echo "flake.nix created. You can customize it as needed." |
| 69 | + else |
| 70 | + echo "flake.nix already exists, skipping creation." |
| 71 | + fi |
| 72 | +} |
| 73 | +# Function to build the extension |
| 74 | +function build_extension { |
| 75 | + local work_dir=$1 |
| 76 | + local output_dir=$2 |
| 77 | + |
| 78 | + echo "Building Torch Extension Bundle from ${work_dir}" |
| 79 | + cd "${work_dir}" |
| 80 | + |
| 81 | + # Check if work_dir is a git repo and get hash if possible |
| 82 | + if [ -d "${work_dir}/.git" ]; then |
| 83 | + # Mark git as safe to allow commands |
| 84 | + git config --global --add safe.directory "${work_dir}" |
| 85 | + # Try to get git revision |
| 86 | + REV=$(git rev-parse --short=8 HEAD) |
| 87 | + |
| 88 | + # Check if working directory is dirty |
| 89 | + if [ -n "$(git status --porcelain 2)" ]; then |
| 90 | + REV="${REV}-dirty" |
| 91 | + fi |
| 92 | + else |
| 93 | + # Generate random material if not a git repo |
| 94 | + REV=$(dd if=/dev/urandom status=none bs=1 count=10 2>/dev/null | base32 | tr '[:upper:]' '[:lower:]' | head -c 10) |
| 95 | + fi |
| 96 | + echo "Building with rev $REV" |
| 97 | + |
| 98 | + # Check for flake.nix or create one |
| 99 | + ensure_flake_exists "${work_dir}" |
| 100 | + |
| 101 | + # Make sure the build is up to date |
| 102 | + nix run .#update-build |
| 103 | + |
| 104 | + # Pure bundle build |
| 105 | + echo "Building with Nix..." |
| 106 | + nix build \ |
| 107 | + . \ |
| 108 | + --max-jobs $MAX_JOBS \ |
| 109 | + -j $CORES \ |
| 110 | + -L |
| 111 | + |
| 112 | + echo "Build completed. Copying results to ${output_dir}" |
| 113 | + mkdir -p "${output_dir}" |
| 114 | + cp -r --dereference ./result/* "${output_dir}/" |
| 115 | + # As root, ensure proper permissions for host access |
| 116 | + chmod -R 777 "${output_dir}" |
| 117 | + echo "Done - results available in ${output_dir}" |
| 118 | +} |
| 119 | +# Function to start a dev shell |
| 120 | +function start_dev_shell { |
| 121 | + echo "Starting development shell..." |
| 122 | + # Check for flake.nix or create one |
| 123 | + ensure_flake_exists "/kernelcode" |
| 124 | + cd /kernelcode |
| 125 | + /root/.nix-profile/bin/nix develop |
| 126 | +} |
| 127 | +# Function to fetch and build from URL |
| 128 | +function fetch_and_build { |
| 129 | + if [ -z "$1" ]; then |
| 130 | + echo "Error: URL required for fetch command" |
| 131 | + show_usage |
| 132 | + exit 1 |
| 133 | + fi |
| 134 | + |
| 135 | + local repo_url="$1" |
| 136 | + local src_dir="/tmp/kernel-src" |
| 137 | + local output_dir="/kernelcode/result" |
| 138 | + |
| 139 | + echo "Fetching code from ${repo_url} to ${src_dir}" |
| 140 | + # Create a temporary directory for the clone |
| 141 | + mkdir -p "${src_dir}" |
| 142 | + |
| 143 | + # Clone the repository to the temporary directory |
| 144 | + git lfs install |
| 145 | + git clone "${repo_url}" "${src_dir}" |
| 146 | + |
| 147 | + # Build from the temporary directory and copy results to mounted output |
| 148 | + build_extension "${src_dir}" "${output_dir}" |
| 149 | +} |
| 150 | +# Parse arguments |
| 151 | +COMMAND="build" # Default command |
| 152 | +ARGS=() |
| 153 | + |
| 154 | +while [[ $# -gt 0 ]]; do |
| 155 | + case $1 in |
| 156 | + build|dev|fetch|help) |
| 157 | + COMMAND="$1" |
| 158 | + shift |
| 159 | + ;; |
| 160 | + --jobs|-j) |
| 161 | + MAX_JOBS="$2" |
| 162 | + shift 2 |
| 163 | + ;; |
| 164 | + --cores|-c) |
| 165 | + CORES="$2" |
| 166 | + shift 2 |
| 167 | + ;; |
| 168 | + -*) |
| 169 | + echo "Unknown option: $1" |
| 170 | + show_usage |
| 171 | + exit 1 |
| 172 | + ;; |
| 173 | + *) |
| 174 | + ARGS+=("$1") |
| 175 | + shift |
| 176 | + ;; |
| 177 | + esac |
| 178 | +done |
| 179 | +# Execute the command |
| 180 | +case $COMMAND in |
| 181 | + build) |
| 182 | + # When building existing code, use the mounted directory |
| 183 | + build_extension "/kernelcode" "/kernelcode/build" |
| 184 | + ;; |
| 185 | + dev) |
| 186 | + start_dev_shell |
| 187 | + ;; |
| 188 | + fetch) |
| 189 | + fetch_and_build "${ARGS[0]}" |
| 190 | + ;; |
| 191 | + help) |
| 192 | + show_usage |
| 193 | + ;; |
| 194 | + *) |
| 195 | + echo "Unknown command: $COMMAND" |
| 196 | + show_usage |
| 197 | + exit 1 |
| 198 | + ;; |
| 199 | +esac |
| 200 | +EOF |
| 201 | +RUN chmod +x /etc/kernel-builder/cli.sh |
| 202 | +# Create output directory structure |
| 203 | +RUN mkdir -p /kernelcode/build |
| 204 | +# Set up volume for kernelcode |
| 205 | +VOLUME /kernelcode |
| 206 | + |
| 207 | +ENTRYPOINT ["/etc/kernel-builder/cli.sh"] |
0 commit comments