diff --git a/README.md b/README.md index d37a5aa..c586e6d 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,10 @@ operation preview version of ghidra with my nix patches +### [`kicad`](./pkgs/kicad-xenia/default.nix) + +preview version of kicad with my patches + ### [`ocamlPackages.ppx_unicode`](./pkgs/ocaml/ppx_unicode) opinionated ppx for string literals: diff --git a/default.nix b/default.nix index c62d8c4..0482b8e 100644 --- a/default.nix +++ b/default.nix @@ -21,6 +21,9 @@ ghidra-extensions = final.lib.recurseIntoAttrs (final.callPackage ./pkgs/ghidra-xenia/extensions.nix { }); ghidra-bin = final.callPackage ./pkgs/ghidra-xenia { }; + kicad = final.callPackage ./pkgs/kicad-xenia { }; + kicadAddons = final.lib.recurseIntoAttrs (final.callPackage ./pkgs/kicad-xenia/addons {}) + ocamlPackages = prev.ocamlPackages.overrideScope (ofinal: oprev: { ppx_unicode = ofinal.callPackage ./pkgs/ocaml/ppx_unicode {}; xlog = ofinal.callPackage ./pkgs/ocaml/xlog {}; diff --git a/pkgs/kicad-xenia/addons/default.nix b/pkgs/kicad-xenia/addons/default.nix new file mode 100644 index 0000000..5170e7e --- /dev/null +++ b/pkgs/kicad-xenia/addons/default.nix @@ -0,0 +1,5 @@ +{ kicad }: +{ + kikit = kicad.callPackage ./kikit.nix { addonName = "kikit"; }; + kikit-library = kicad.callPackage ./kikit.nix { addonName = "kikit-library"; }; +} diff --git a/pkgs/kicad-xenia/addons/kikit.nix b/pkgs/kicad-xenia/addons/kikit.nix new file mode 100644 index 0000000..6e5fc5a --- /dev/null +++ b/pkgs/kicad-xenia/addons/kikit.nix @@ -0,0 +1,52 @@ +# For building the multiple addons that are in the kikit repo. +{ stdenv +, bc +, kikit +, zip +, python3 +, addonName +, addonPath +}: +let + # This python is only used when building the package, it's not the python + # environment that will ultimately run the code packaged here. The python env defined + # in KiCad will import the python code packaged here when KiCad starts up. + python = python3.withPackages (ps: with ps; [ click ]); + kikit-module = python3.pkgs.toPythonModule (kikit.override { inherit python3; }); + + # The following different addons can be built from the same source. + targetSpecs = { + "kikit" = { + makeTarget = "pcm-kikit"; + resultZip = "pcm-kikit.zip"; + description = "KiCad plugin and a CLI tool to automate several tasks in a standard KiCad workflow"; + }; + "kikit-library" = { + makeTarget = "pcm-lib"; + resultZip = "pcm-kikit-lib.zip"; + description = "KiKit uses these symbols and footprints to annotate your boards (e.g., to place a tab in a panel)."; + }; + }; + targetSpec = targetSpecs.${addonName}; +in +stdenv.mkDerivation { + name = "kicadaddon-${addonName}"; + inherit (kikit-module) src version; + + nativeBuildInputs = [ python bc zip ]; + propagatedBuildInputs = [ kikit-module ]; + + buildPhase = '' + patchShebangs scripts/setJson.py + make ${targetSpec.makeTarget} + ''; + + installPhase = '' + mkdir $out + mv build/${targetSpec.resultZip} $out/${addonPath} + ''; + + meta = kikit-module.meta // { + description = targetSpec.description; + }; +} diff --git a/pkgs/kicad-xenia/base.nix b/pkgs/kicad-xenia/base.nix new file mode 100644 index 0000000..b5f721c --- /dev/null +++ b/pkgs/kicad-xenia/base.nix @@ -0,0 +1,211 @@ +{ lib +, stdenv +, cmake +, libGLU +, libGL +, zlib +, wxGTK +, gtk3 +, libX11 +, gettext +, glew +, glm +, cairo +, curl +, openssl +, boost +, pkg-config +, doxygen +, graphviz +, pcre +, libpthreadstubs +, libXdmcp +, unixODBC +, libgit2 +, libsecret +, libgcrypt +, libgpg-error + +, util-linux +, libselinux +, libsepol +, libthai +, libdatrie +, libxkbcommon +, libepoxy +, dbus +, at-spi2-core +, libXtst +, pcre2 +, libdeflate + +, swig4 +, python +, wxPython +, opencascade-occt_7_6 +, libngspice +, valgrind + +, stable +, testing +, baseName +, kicadSrc +, kicadVersion +, withNgspice +, withScripting +, withI18n +, debug +, sanitizeAddress +, sanitizeThreads +}: + +assert lib.assertMsg (!(sanitizeAddress && sanitizeThreads)) + "'sanitizeAddress' and 'sanitizeThreads' are mutually exclusive, use one."; +assert testing -> !stable + -> throw "testing implies stable and cannot be used with stable = false"; + +let + opencascade-occt = opencascade-occt_7_6; + inherit (lib) optional optionals optionalString; +in +stdenv.mkDerivation rec { + pname = "kicad-base"; + version = if (stable) then kicadVersion else builtins.substring 0 10 src.rev; + + src = kicadSrc; + + patches = [ + # upstream issue 12941 (attempted to upstream, but appreciably unacceptable) + ./writable.patch + # https://gitlab.com/kicad/code/kicad/-/issues/15687 + ./runtime_stock_data_path.patch + ]; + + # tagged releases don't have "unknown" + # kicad testing and nightlies use git describe --dirty + # nix removes .git, so its approximated here + postPatch = lib.optionalString (!stable || testing) '' + substituteInPlace cmake/KiCadVersion.cmake \ + --replace "unknown" "${builtins.substring 0 10 src.rev}" + + substituteInPlace cmake/CreateGitVersionHeader.cmake \ + --replace "0000000000000000000000000000000000000000" "${src.rev}" + ''; + + makeFlags = optionals (debug) [ "CFLAGS+=-Og" "CFLAGS+=-ggdb" ]; + + cmakeFlags = [ + "-DKICAD_USE_EGL=ON" + "-DOCC_INCLUDE_DIR=${opencascade-occt}/include/opencascade" + # https://gitlab.com/kicad/code/kicad/-/issues/17133 + "-DCMAKE_CTEST_ARGUMENTS='--exclude-regex;qa_spice'" + ] + ++ optional (stdenv.hostPlatform.system == "aarch64-linux") + "-DCMAKE_CTEST_ARGUMENTS=--exclude-regex;'qa_spice|qa_cli'" + ++ optional (stable && !withNgspice) "-DKICAD_SPICE=OFF" + ++ optionals (!withScripting) [ + "-DKICAD_SCRIPTING_WXPYTHON=OFF" + ] + ++ optionals (withI18n) [ + "-DKICAD_BUILD_I18N=ON" + ] + ++ optionals (!doInstallCheck) [ + "-DKICAD_BUILD_QA_TESTS=OFF" + ] + ++ optionals (debug) [ + "-DKICAD_STDLIB_DEBUG=ON" + "-DKICAD_USE_VALGRIND=ON" + ] + ++ optionals (sanitizeAddress) [ + "-DKICAD_SANITIZE_ADDRESS=ON" + ] + ++ optionals (sanitizeThreads) [ + "-DKICAD_SANITIZE_THREADS=ON" + ]; + + cmakeBuildType = if debug then "Debug" else "Release"; + + nativeBuildInputs = [ + cmake + doxygen + graphviz + pkg-config + libgit2 + libsecret + libgcrypt + libgpg-error + ] + # wanted by configuration on linux, doesn't seem to affect performance + # no effect on closure size + ++ optionals (stdenv.isLinux) [ + util-linux + libselinux + libsepol + libthai + libdatrie + libxkbcommon + libepoxy + dbus + at-spi2-core + libXtst + pcre2 + ]; + + buildInputs = [ + libGLU + libGL + zlib + libX11 + wxGTK + gtk3 + pcre + libXdmcp + gettext + glew + glm + libpthreadstubs + cairo + curl + openssl + boost + swig4 + python + unixODBC + libdeflate + opencascade-occt + ] + ++ optional (withScripting) wxPython + ++ optional (withNgspice) libngspice + ++ optional (debug) valgrind; + + # some ngspice tests attempt to write to $HOME/.cache/ + # this could be and was resolved with XDG_CACHE_HOME = "$TMP"; + # but failing tests still attempt to create $HOME + # and the newer CLI tests seem to also use $HOME... + HOME = "$TMP"; + + # debug builds fail all but the python test + doInstallCheck = !(debug); + installCheckTarget = "test"; + + nativeInstallCheckInputs = [ + (python.withPackages(ps: with ps; [ + numpy + pytest + cairosvg + pytest-image-diff + ])) + ]; + + dontStrip = debug; + + meta = { + description = "Just the built source without the libraries"; + longDescription = '' + Just the build products, the libraries are passed via an env var in the wrapper, default.nix + ''; + homepage = "https://www.kicad.org/"; + license = lib.licenses.gpl3Plus; + platforms = lib.platforms.all; + }; +} diff --git a/pkgs/kicad-xenia/default.nix b/pkgs/kicad-xenia/default.nix new file mode 100644 index 0000000..381452f --- /dev/null +++ b/pkgs/kicad-xenia/default.nix @@ -0,0 +1,298 @@ +{ lib, stdenv +, runCommand +, newScope +, fetchFromGitLab +, fetchgit +, makeWrapper +, symlinkJoin +, callPackage +, callPackages + +, gnome +, dconf +, gtk3 +, wxGTK32 +, librsvg +, cups +, gsettings-desktop-schemas +, hicolor-icon-theme + +, unzip +, jq + +, pname ? "kicad" +, stable ? true +, testing ? false +, withNgspice ? !stdenv.isDarwin +, libngspice +, withScripting ? true +, python3 +, addons ? [ ] +, debug ? false +, sanitizeAddress ? false +, sanitizeThreads ? false +, with3d ? true +, withI18n ? true +, srcs ? { } +}: + +# `addons`: https://dev-docs.kicad.org/en/addons/ +# +# ```nix +# kicad = pkgs.kicad.override { +# addons = with pkgs.kicadAddons; [ kikit kikit-library ]; +# }; +# ``` + +# The `srcs` parameter can be used to override the kicad source code +# and all libraries, which are otherwise inaccessible +# to overlays since most of the kicad build expression has been +# refactored into base.nix, most of the library build expressions have +# been refactored into libraries.nix. Overrides are only applied when +# building `kicad-unstable`. The `srcs` parameter has +# no effect for stable `kicad`. `srcs` takes an attribute set in which +# any of the following attributes are meaningful (though none are +# mandatory): "kicad", "kicadVersion", "symbols", "templates", +# "footprints", "packages3d", and "libVersion". "kicadVersion" and +# "libVersion" should be set to a string with the desired value for +# the version attribute in kicad's `mkDerivation` and the version +# attribute in any of the library's `mkDerivation`, respectively. +# "kicad", "symbols", "templates", "footprints", and "packages3d" +# should be set to an appropriate fetcher (e.g. `fetchFromGitLab`). +# So, for example, a possible overlay for kicad is: +# +# final: prev: + +# { +# kicad-unstable = (prev.kicad-unstable.override { +# srcs = { +# kicadVersion = "2020-10-08"; +# kicad = prev.fetchFromGitLab { +# group = "kicad"; +# owner = "code"; +# repo = "kicad"; +# rev = "fd22fe8e374ce71d57e9f683ba996651aa69fa4e"; +# sha256 = "sha256-F8qugru/jU3DgZSpQXQhRGNFSk0ybFRkpyWb7HAGBdc="; +# }; +# }; +# }); +# } + +let + baseName = if (testing) then "kicad-testing" + else if (stable) then "kicad" + else "kicad-unstable"; + versionsImport = import ./versions.nix; + + # versions.nix does not provide us with version, src and rev. We + # need to turn this into approprate fetcher calls. + #kicadSrcFetch = fetchFromGitLab { + # group = "kicad"; + # owner = "code"; + # repo = "kicad"; + # rev = versionsImport.${baseName}.kicadVersion.src.rev; + # sha256 = versionsImport.${baseName}.kicadVersion.src.sha256; + #}; + kicadSrcFetch = fetchgit { + url = "https://git.lain.faith/haskal/kicad.git"; + rev = versionsImport.${baseName}.kicadVersion.src.rev; + sha256 = versionsImport.${baseName}.kicadVersion.src.sha256; + }; + + libSrcFetch = name: fetchFromGitLab { + group = "kicad"; + owner = "libraries"; + repo = "kicad-${name}"; + rev = versionsImport.${baseName}.libVersion.libSources.${name}.rev; + sha256 = versionsImport.${baseName}.libVersion.libSources.${name}.sha256; + }; + + # only override `src` or `version` if building `kicad-unstable` with + # the appropriate attribute defined in `srcs`. + srcOverridep = attr: (!stable && builtins.hasAttr attr srcs); + + # use default source and version (as defined in versions.nix) by + # default, or use the appropriate attribute from `srcs` if building + # unstable with `srcs` properly defined. + kicadSrc = + if srcOverridep "kicad" then srcs.kicad + else kicadSrcFetch; + kicadVersion = + if srcOverridep "kicadVersion" then srcs.kicadVersion + else versionsImport.${baseName}.kicadVersion.version; + + libSrc = name: if srcOverridep name then srcs.${name} else libSrcFetch name; + # TODO does it make sense to only have one version for all libs? + libVersion = + if srcOverridep "libVersion" then srcs.libVersion + else versionsImport.${baseName}.libVersion.version; + + wxGTK = wxGTK32; + python = python3; + wxPython = python.pkgs.wxpython; + addonPath = "addon.zip"; + addonsDrvs = map (pkg: pkg.override { inherit addonPath python3; }) addons; + + addonsJoined = + runCommand "addonsJoined" + { + inherit addonsDrvs; + nativeBuildInputs = [ unzip jq ]; + } '' + mkdir $out + + for pkg in $addonsDrvs; do + unzip $pkg/addon.zip -d unpacked + + folder_name=$(jq .identifier unpacked/metadata.json --raw-output | tr . _) + for d in unpacked/*; do + if [ -d "$d" ]; then + dest=$out/share/kicad/scripting/$(basename $d)/$folder_name + mkdir -p $(dirname $dest) + + mv $d $dest + fi + done + rm -r unpacked + done + ''; + + inherit (lib) concatStringsSep flatten optionalString optionals; +in +stdenv.mkDerivation rec { + + # Common libraries, referenced during runtime, via the wrapper. + passthru.libraries = callPackages ./libraries.nix { inherit libSrc; }; + passthru.callPackage = newScope { inherit addonPath python3; }; + base = callPackage ./base.nix { + inherit stable testing baseName; + inherit kicadSrc kicadVersion; + inherit wxGTK python wxPython; + inherit withNgspice withScripting withI18n; + inherit debug sanitizeAddress sanitizeThreads; + }; + + inherit pname; + version = if (stable) then kicadVersion else builtins.substring 0 10 src.src.rev; + + src = base; + dontUnpack = true; + dontConfigure = true; + dontBuild = true; + dontFixup = true; + + pythonPath = optionals (withScripting) + [ wxPython python.pkgs.six python.pkgs.requests ] ++ addonsDrvs; + + nativeBuildInputs = [ makeWrapper ] + ++ optionals (withScripting) + [ python.pkgs.wrapPython ]; + + # KICAD7_TEMPLATE_DIR only works with a single path (it does not handle : separated paths) + # but it's used to find both the templates and the symbol/footprint library tables + # https://gitlab.com/kicad/code/kicad/-/issues/14792 + template_dir = symlinkJoin { + name = "KiCad_template_dir"; + paths = with passthru.libraries; [ + "${templates}/share/kicad/template" + "${footprints}/share/kicad/template" + "${symbols}/share/kicad/template" + ]; + }; + # We are emulating wrapGAppsHook3, along with other variables to the wrapper + makeWrapperArgs = with passthru.libraries; [ + "--prefix XDG_DATA_DIRS : ${base}/share" + "--prefix XDG_DATA_DIRS : ${hicolor-icon-theme}/share" + "--prefix XDG_DATA_DIRS : ${gnome.adwaita-icon-theme}/share" + "--prefix XDG_DATA_DIRS : ${gtk3}/share/gsettings-schemas/${gtk3.name}" + "--prefix XDG_DATA_DIRS : ${gsettings-desktop-schemas}/share/gsettings-schemas/${gsettings-desktop-schemas.name}" + # wrapGAppsHook3 did these two as well, no idea if it matters... + "--prefix XDG_DATA_DIRS : ${cups}/share" + "--prefix GIO_EXTRA_MODULES : ${dconf}/lib/gio/modules" + # required to open a bug report link in firefox-wayland + "--set-default MOZ_DBUS_REMOTE 1" + "--set-default KICAD8_FOOTPRINT_DIR ${footprints}/share/kicad/footprints" + "--set-default KICAD8_SYMBOL_DIR ${symbols}/share/kicad/symbols" + "--set-default KICAD8_TEMPLATE_DIR ${template_dir}" + ] + ++ optionals (addons != [ ]) ( + let stockDataPath = symlinkJoin { + name = "kicad_stock_data_path"; + paths = [ + "${base}/share/kicad" + "${addonsJoined}/share/kicad" + ]; + }; + in + [ "--set-default NIX_KICAD8_STOCK_DATA_PATH ${stockDataPath}" ] + ) + ++ optionals (with3d) + [ + "--set-default KICAD8_3DMODEL_DIR ${packages3d}/share/kicad/3dmodels" + ] + ++ optionals (withNgspice) [ "--prefix LD_LIBRARY_PATH : ${libngspice}/lib" ] + + # infinisil's workaround for #39493 + ++ [ "--set GDK_PIXBUF_MODULE_FILE ${librsvg}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache" ] + ; + + # why does $makeWrapperArgs have to be added explicitly? + # $out and $program_PYTHONPATH don't exist when makeWrapperArgs gets set? + installPhase = + let + bin = if stdenv.isDarwin then "*.app/Contents/MacOS" else "bin"; + tools = [ "kicad" "pcbnew" "eeschema" "gerbview" "pcb_calculator" "pl_editor" "bitmap2component" ]; + utils = [ "dxf2idf" "idf2vrml" "idfcyl" "idfrect" "kicad-cli" ]; + in + (concatStringsSep "\n" + (flatten [ + "runHook preInstall" + + (optionalString (withScripting) "buildPythonPath \"${base} $pythonPath\" \n") + + # wrap each of the directly usable tools + (map + (tool: "makeWrapper ${base}/${bin}/${tool} $out/bin/${tool} $makeWrapperArgs" + + optionalString (withScripting) " --set PYTHONPATH \"$program_PYTHONPATH\"" + ) + tools) + + # link in the CLI utils + (map (util: "ln -s ${base}/${bin}/${util} $out/bin/${util}") utils) + + "runHook postInstall" + ]) + ) + ; + + postInstall = '' + mkdir -p $out/share + ln -s ${base}/share/applications $out/share/applications + ln -s ${base}/share/icons $out/share/icons + ln -s ${base}/share/mime $out/share/mime + ln -s ${base}/share/metainfo $out/share/metainfo + ''; + + passthru.updateScript = { + command = [ ./update.sh "${pname}" ]; + supportedFeatures = [ "commit" ]; + }; + + meta = rec { + description = (if (stable) + then "Open Source Electronics Design Automation suite" + else if (testing) then "Open Source EDA suite, latest on stable branch" + else "Open Source EDA suite, latest on master branch") + + (lib.optionalString (!with3d) ", without 3D models"); + homepage = "https://www.kicad.org/"; + longDescription = '' + KiCad is an open source software suite for Electronic Design Automation. + The Programs handle Schematic Capture, and PCB Layout with Gerber output. + ''; + license = lib.licenses.gpl3Plus; + maintainers = with lib.maintainers; [ evils ]; + platforms = lib.platforms.all; + broken = stdenv.isDarwin; + mainProgram = "kicad"; + }; +} diff --git a/pkgs/kicad-xenia/libraries.nix b/pkgs/kicad-xenia/libraries.nix new file mode 100644 index 0000000..327f77d --- /dev/null +++ b/pkgs/kicad-xenia/libraries.nix @@ -0,0 +1,39 @@ +{ lib, stdenv +, cmake +, gettext +, libSrc +, stepreduce +, parallel +, zip +}: +let + mkLib = name: + stdenv.mkDerivation { + pname = "kicad-${name}"; + version = builtins.substring 0 10 (libSrc name).rev; + + src = libSrc name; + + nativeBuildInputs = [ cmake ] + ++ lib.optionals (name == "packages3d") [ + stepreduce + parallel + zip + ]; + + postInstall = lib.optional (name == "packages3d") '' + find $out -type f -name '*.step' | parallel 'stepreduce {} {} && zip -9 {.}.stpZ {} && rm {}' + ''; + + meta = rec { + license = lib.licenses.cc-by-sa-40; + platforms = lib.platforms.all; + }; + }; +in +{ + symbols = mkLib "symbols"; + templates = mkLib "templates"; + footprints = mkLib "footprints"; + packages3d = mkLib "packages3d"; +} diff --git a/pkgs/kicad-xenia/runtime_stock_data_path.patch b/pkgs/kicad-xenia/runtime_stock_data_path.patch new file mode 100644 index 0000000..43e99a5 --- /dev/null +++ b/pkgs/kicad-xenia/runtime_stock_data_path.patch @@ -0,0 +1,15 @@ +diff --git a/common/paths.cpp b/common/paths.cpp +index a74cdd9..790cc58 100644 +--- a/common/paths.cpp ++++ b/common/paths.cpp +@@ -151,6 +151,10 @@ wxString PATHS::GetStockDataPath( bool aRespectRunFromBuildDir ) + { + wxString path; + ++ if( wxGetEnv( wxT( "NIX_KICAD8_STOCK_DATA_PATH" ), &path ) ) { ++ return path; ++ } ++ + if( aRespectRunFromBuildDir && wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) ) + { + // Allow debugging from build dir by placing relevant files/folders in the build root diff --git a/pkgs/kicad-xenia/update.sh b/pkgs/kicad-xenia/update.sh new file mode 100755 index 0000000..b47e2d8 --- /dev/null +++ b/pkgs/kicad-xenia/update.sh @@ -0,0 +1,260 @@ +#!/usr/bin/env nix-shell +#!nix-shell -i bash -p coreutils git nix curl jq +# shellcheck shell=bash enable=all + +set -e +shopt -s inherit_errexit + +# this script will generate versions.nix in the right location +# this should contain the versions' revs and hashes +# the stable revs are stored only for ease of skipping + +# by default nix-prefetch-url uses XDG_RUNTIME_DIR as tmp +# which is /run/user/1000, which defaults to 10% of your RAM +# unless you have over 64GB of ram that'll be insufficient +# resulting in "tar: no space left on device" for packages3d +# hence: +export TMPDIR=/tmp + +# if something goes unrepairably wrong, run 'update.sh all clean' + +# TODO +# support parallel instances for each pname +# currently risks reusing old data +# no getting around manually checking if the build product works... +# if there is, default to commiting? +# won't work when running in parallel? +# remove items left in /nix/store? +# reuse hashes of already checked revs (to avoid redownloading testing's packages3d) + +# nixpkgs' update.nix passes in UPDATE_NIX_PNAME to indicate which package is being updated +# assigning a default value to that as shellcheck doesn't like the use of unassigned variables +: "${UPDATE_NIX_PNAME:=""}" +# update.nix can also parse JSON output of this script to formulate a commit +# this requires we collect the version string in the old versions.nix for the updated package +old_version="" +new_version="" + + +# get the latest tag that isn't an RC or *.99 +latest_tags="$(git ls-remote --tags --sort -version:refname https://gitlab.com/kicad/code/kicad.git)" +# using a scratch variable to ensure command failures get caught (SC2312) +scratch="$(grep -o 'refs/tags/[0-9]*\.[0-9]*\.[0-9]*$' <<< "${latest_tags}")" +scratch="$(grep -ve '\.99' -e '\.9\.9' <<< "${scratch}")" +scratch="$(sed -n '1p' <<< "${scratch}")" +latest_tag="$(cut -d '/' -f 3 <<< "${scratch}")" + +# get the latest branch name for testing +branches="$(git ls-remote --heads --sort -version:refname https://gitlab.com/kicad/code/kicad.git)" +scratch="$(grep -o 'refs/heads/[0-9]*\.[0-9]*$' <<< "${branches}")" +scratch="$(sed -n '1p' <<< "${scratch}")" +testing_branch="$(cut -d '/' -f 3 <<< "${scratch}")" + +# "latest_tag" and "master" directly refer to what we want +# "testing" uses "testing_branch" found above +all_versions=( "${latest_tag}" testing master ) + +prefetch="nix-prefetch-url --unpack --quiet" + +clean="" +check_stable="" +check_testing=1 +check_unstable=1 +commit="" + +for arg in "$@" "${UPDATE_NIX_PNAME}"; do + case "${arg}" in + help|-h|--help) echo "Read me!" >&2; exit 1; ;; + kicad|kicad-small|release|tag|stable|5*|6*|7*|8*) check_stable=1; check_testing=""; check_unstable="" ;; + *testing|kicad-testing-small) check_testing=1; check_unstable="" ;; + *unstable|*unstable-small|master|main) check_unstable=1; check_testing="" ;; + latest|now|today) check_unstable=1; check_testing=1 ;; + all|both|full) check_stable=1; check_testing=1; check_unstable=1 ;; + clean|fix|*fuck) check_stable=1; check_testing=1; check_unstable=1; clean=1 ;; + commit) commit=1 ;; + *) ;; + esac +done + +here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +commit_date() { + gitlab_json="$(curl -s https://gitlab.com/api/v4/projects/kicad%2Fcode%2Fkicad/repository/commits/"$1")" + commit_created="$(jq .created_at --raw-output <<< "${gitlab_json}")" + date --date="${commit_created}" --iso-8601 --utc +} + +file="${here}/versions.nix" +# just in case this runs in parallel +tmp="${here}/,versions.nix.${RANDOM}" + +libs=( symbols templates footprints packages3d ) + +get_rev() { + git ls-remote "$@" +} + +gitlab="https://gitlab.com/kicad" +# append commit hash or tag +src_pre="https://gitlab.com/api/v4/projects/kicad%2Fcode%2Fkicad/repository/archive.tar.gz?sha=" +lib_pre="https://gitlab.com/api/v4/projects/kicad%2Flibraries%2Fkicad-" +lib_mid="/repository/archive.tar.gz?sha=" + +# number of items updated +count=0 + +printf "Latest tag is %s\n" "${latest_tag}" >&2 + +if [[ ! -f ${file} ]]; then + echo "No existing file, generating from scratch" >&2 + check_stable=1; check_testing=1; check_unstable=1; clean=1 +fi + +printf "Writing %s\n" "${tmp}" >&2 + +# not a dangling brace, grouping the output to redirect to file +{ + +printf "# This file was generated by update.sh\n\n" +printf "{\n" + +for version in "${all_versions[@]}"; do + + src_version=${version}; + lib_version=${version}; + # testing is the stable branch on the main repo + # but the libraries don't have such a branch + # only the latest release tag and a master branch + if [[ ${version} == "testing" ]]; then + src_version=${testing_branch}; + lib_version=${latest_tag}; + fi + + if [[ ${version} == "master" ]]; then + pname="kicad-unstable" + elif [[ ${version} == "testing" ]]; then + pname="kicad-testing" + else + pname="kicad" + fi + + # skip a version if we don't want to check it + if [[ (-n ${check_stable} && ${version} != "master" && ${version} != "testing") \ + || (-n ${check_testing} && ${version} == "testing") \ + || (-n ${check_unstable} && ${version} == "master" ) ]]; then + + now=$(commit_date "${src_version}") + + if [[ ${version} == "master" ]]; then + pname="kicad-unstable" + new_version="${now}" + elif [[ ${version} == "testing" ]]; then + pname="kicad-testing" + new_version="${testing_branch}-${now}" + else + pname="kicad" + new_version="${version}" + fi + + printf "\nChecking %s\n" "${pname}" >&2 + + printf "%2s\"%s\" = {\n" "" "${pname}" + printf "%4skicadVersion = {\n" "" + printf "%6sversion =\t\t\t\"%s\";\n" "" "${new_version}" + printf "%6ssrc = {\n" "" + + echo "Checking src" >&2 + scratch="$(get_rev "${gitlab}"/code/kicad.git "${src_version}")" + src_rev="$(cut -f1 <<< "${scratch}")" + has_rev="$(grep -sm 1 "\"${pname}\"" -A 4 "${file}" | grep -sm 1 "${src_rev}" || true)" + has_hash="$(grep -sm 1 "\"${pname}\"" -A 5 "${file}" | grep -sm 1 "sha256" || true)" + old_version="$(grep -sm 1 "\"${pname}\"" -A 3 "${file}" | grep -sm 1 "version" | awk -F "\"" '{print $2}' || true)" + + if [[ -n ${has_rev} && -n ${has_hash} && -z ${clean} ]]; then + echo "Reusing old ${pname}.src.sha256, already latest .rev at ${old_version}" >&2 + scratch=$(grep -sm 1 "\"${pname}\"" -A 5 "${file}") + grep -sm 1 "rev" -A 1 <<< "${scratch}" + else + prefetched="$(${prefetch} "${src_pre}${src_rev}")" + printf "%8srev =\t\t\t\"%s\";\n" "" "${src_rev}" + printf "%8ssha256 =\t\t\"%s\";\n" "" "${prefetched}" + count=$((count+1)) + fi + printf "%6s};\n" "" + printf "%4s};\n" "" + + printf "%4slibVersion = {\n" "" + printf "%6sversion =\t\t\t\"%s\";\n" "" "${new_version}" + printf "%6slibSources = {\n" "" + + for lib in "${libs[@]}"; do + echo "Checking ${lib}" >&2 + url="${gitlab}/libraries/kicad-${lib}.git" + scratch="$(get_rev "${url}" "${lib_version}")" + scratch="$(cut -f1 <<< "${scratch}")" + lib_rev="$(tail -n1 <<< "${scratch}")" + has_rev="$(grep -sm 1 "\"${pname}\"" -A 19 "${file}" | grep -sm 1 "${lib_rev}" || true)" + has_hash="$(grep -sm 1 "\"${pname}\"" -A 20 "${file}" | grep -sm 1 "${lib}.sha256" || true)" + if [[ -n ${has_rev} && -n ${has_hash} && -z ${clean} ]]; then + echo "Reusing old kicad-${lib}-${new_version}.src.sha256, already latest .rev" >&2 + scratch="$(grep -sm 1 "\"${pname}\"" -A 20 "${file}")" + grep -sm 1 "${lib}" -A 1 <<< "${scratch}" + else + prefetched="$(${prefetch} "${lib_pre}${lib}${lib_mid}${lib_rev}")" + printf "%8s%s.rev =\t" "" "${lib}" + case "${lib}" in + symbols|templates) printf "\t" ;; *) ;; + esac + printf "\"%s\";\n" "${lib_rev}" + printf "%8s%s.sha256 =\t\"%s\";\n" "" "${lib}" "${prefetched}" + count=$((count+1)) + fi + done + printf "%6s};\n" "" + printf "%4s};\n" "" + printf "%2s};\n" "" + else + printf "\nReusing old %s\n" "${pname}" >&2 + grep -sm 1 "\"${pname}\"" -A 21 "${file}" + fi +done +printf "}\n" +} > "${tmp}" + +if grep '""' "${tmp}"; then + echo "empty value detected, out of space?" >&2 + exit "1" +fi + +mv "${tmp}" "${file}" + +printf "\nFinished\nMoved output to %s\n\n" "${file}" >&2 + +if [[ ${count} -gt 0 ]]; then + if [[ ${count} -gt 1 ]]; then s="s"; else s=""; fi + echo "${count} revision${s} changed" >&2 + if [[ -n ${commit} ]]; then + git commit -am "$(printf "kicad: automatic update of %s item%s\n" "${count}" "${s}")" + fi + echo "Please confirm the new versions.nix works before making a PR." >&2 +else + echo "No changes, those checked are up to date" >&2 +fi + +# using UPDATE_NIX_ATTR_PATH to detect if this is being called from update.nix +# and output JSON to describe the changes +if [[ -n ${UPDATE_NIX_ATTR_PATH} ]]; then + + if [[ ${count} -eq 0 ]]; then echo "[{}]"; exit 0; fi + + jq -n \ + --arg attrpath "${UPDATE_NIX_PNAME}" \ + --arg oldversion "${old_version}" \ + --arg newversion "${new_version}" \ + --arg file "${file}" \ +'[{ + "attrPath": $attrpath, + "oldVersion": $oldversion, + "newVersion": $newversion, + "files": [ $file ] +}]' +fi diff --git a/pkgs/kicad-xenia/versions.nix b/pkgs/kicad-xenia/versions.nix new file mode 100644 index 0000000..2bdc697 --- /dev/null +++ b/pkgs/kicad-xenia/versions.nix @@ -0,0 +1,70 @@ +# This file was generated by update.sh + +{ + "kicad" = { + kicadVersion = { + version = "8.0.2"; + src = { + rev = "2d5434e9abf570ffd19b22c90963ea71cfb91d3d"; + sha256 = "1n1jj7559xd4ib4c6ybya75a5hbarnkfy8gxzxfw58wdb4lxxmzz"; + }; + }; + libVersion = { + version = "8.0.2"; + libSources = { + symbols.rev = "099ac0c8ac402a685fde00b1369e34a116e29661"; + symbols.sha256 = "0w333f89yw2m0zlpkg0k6hfwlj10snm8laihdjnsb22asyz4pbhn"; + templates.rev = "2e2da58e02707d327d59d4101c401a82dc9a26f6"; + templates.sha256 = "073a6cyvzzy0vmkj3ip4ziq7b7pcizs70nm5acw838dxghjfyv3v"; + footprints.rev = "e8c30550cde4945cbe1bf30cccf0b3c1e2bda6c6"; + footprints.sha256 = "10j8qjljc1fv8k4zp3zn0da33g57hn6pgrgmbgp18dsa539xvxcz"; + packages3d.rev = "249f7947587529026e1676cd70c8d7493a8d8162"; + packages3d.sha256 = "04gvfb54jhnww2qwrxc27wpyrvmjasdc4xhr0ridl7dglh4qcp35"; + }; + }; + }; +# "kicad-testing" = { +# kicadVersion = { +# version = "8.0-2024-02-23"; +# src = { +# rev = "14d71c8ca6b48d2eb956bb069acf05a37b1b2652"; +# sha256 = "0xqd0xbpnvsvba75526nwgzr8l2cfxy99sjmg13sjxfx7rq16kqi"; +# }; +# }; +# libVersion = { +# version = "8.0-2024-02-23"; +# libSources = { +# symbols.rev = "e228d4e8b295364e90e36c57f4023d8285ba88cd"; +# symbols.sha256 = "049h2a7yn6ks8sybppixa872dbvyd0rwf9r6nixvdg6d13fl6rwf"; +# templates.rev = "2e00c233b67e35323f90d04c190bf70237a252f2"; +# templates.sha256 = "0m9bggz3cm27kqpjjwxy19mqzk0c69bywcjkqcni7kafr21c6k4z"; +# footprints.rev = "6e5329a6d4aaa81290e23af3eba88f505c2f61b0"; +# footprints.sha256 = "0ypjlbmzmcl3pha3q2361va70c988b1drxy8320gm66jkzfc21a1"; +# packages3d.rev = "d1e521228d9f5888836b1a6a35fb05fb925456fa"; +# packages3d.sha256 = "0lcy1av7ixg1f7arflk50jllpc1749sfvf3h62hkxsz97wkr97xj"; +# }; +# }; +# }; +# "kicad-unstable" = { +# kicadVersion = { +# version = "2024-02-23"; +# src = { +# rev = "b7b64d959f37f00bb0d14b007c3b3908196e1024"; +# sha256 = "1gl7mjqpmqq4m55z6crwb77983g00gi2161ichsc7hsfhs4c8grh"; +# }; +# }; +# libVersion = { +# version = "2024-02-23"; +# libSources = { +# symbols.rev = "8b0c343d8694fe0a968e5c4af69fd161bacf7da1"; +# symbols.sha256 = "049h2a7yn6ks8sybppixa872dbvyd0rwf9r6nixvdg6d13fl6rwf"; +# templates.rev = "0a6c4f798a68a5c639d54b4d3093460ab9267816"; +# templates.sha256 = "0m9bggz3cm27kqpjjwxy19mqzk0c69bywcjkqcni7kafr21c6k4z"; +# footprints.rev = "ded6b053460faae5783c538a38e91e2b4bddcf2e"; +# footprints.sha256 = "035bf37n4vrihaj4zfdncisdx9fly1vya7lhkxhlsbv5blpi4a5y"; +# packages3d.rev = "984667325076d4e50dab14e755aeacf97f42194c"; +# packages3d.sha256 = "0lkaxv02h4sxrnm8zr17wl9d07mazlisad78r35gry741i362cdg"; +# }; +# }; +# }; +} diff --git a/pkgs/kicad-xenia/writable.patch b/pkgs/kicad-xenia/writable.patch new file mode 100644 index 0000000..a2969f2 --- /dev/null +++ b/pkgs/kicad-xenia/writable.patch @@ -0,0 +1,49 @@ +commit 6a72fd032405515e468797be91b5a6ebcbbb5fd8 +Author: Evils +Date: Wed Nov 23 19:49:13 2022 +0100 + + ensure new projects are writable + +diff --git a/kicad/kicad_manager_frame.cpp b/kicad/kicad_manager_frame.cpp +index 7ee8090858..391514519c 100644 +--- a/kicad/kicad_manager_frame.cpp ++++ b/kicad/kicad_manager_frame.cpp +@@ -638,6 +638,12 @@ void KICAD_MANAGER_FRAME::CreateNewProject( const wxFileName& aProjectFileName, + + // wxFFile dtor will close the file + } ++ ++ if( destFileName.IsOk() && !destFileName.IsFileWritable() ) ++ { ++ destFileName.SetPermissions(0644); ++ } ++ + } + } + +diff --git a/kicad/project_template.cpp b/kicad/project_template.cpp +index bf951fcddb..2bef94326b 100644 +--- a/kicad/project_template.cpp ++++ b/kicad/project_template.cpp +@@ -282,6 +282,21 @@ bool PROJECT_TEMPLATE::CreateProject( wxFileName& aNewProjectPath, wxString* aEr + + result = false; + } ++ else if( !destFile.IsFileWritable() && !destFile.SetPermissions(0644) ) ++ { ++ if( aErrorMsg ) ++ { ++ if( !aErrorMsg->empty() ) ++ *aErrorMsg += "\n"; ++ ++ wxString msg; ++ ++ msg.Printf( _( "Cannot make file writable: '%s'." ), destFile.GetFullPath() ); ++ *aErrorMsg += msg; ++ } ++ ++ result = false; ++ } + } + + return result;