mirror of
https://github.com/nix-community/nixvim.git
synced 2025-06-20 16:15:43 +02:00
update-scripts: move out of flake
See the explanation in the new update-scripts/README.md file.
This commit is contained in:
parent
96d0a2e390
commit
d3cb750e6a
10 changed files with 146 additions and 88 deletions
30
update-scripts/README.md
Normal file
30
update-scripts/README.md
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Update scripts
|
||||
|
||||
This directory contains update scripts that are not part of the actual flake.
|
||||
|
||||
These scripts are used by the `update` CI workflow, so you shouldn't need to run them manually.
|
||||
This workflow is found at `.github/workflows/update.yml`.
|
||||
|
||||
## Developing
|
||||
|
||||
Because these scripts aren't packaged in the flake, you should use `nix-build` and `nix-shell` instead of `nix build`, `nix run`, and `nix develop`, etc.
|
||||
|
||||
For example, `nix-build -A generate` will build `./generate.nix` into `./result/bin/generate`.
|
||||
|
||||
A `shell.nix` is available that will place `generate` on your PATH.
|
||||
|
||||
You could use this directory's shell/packages from another working directory by supplying `nix-build` or `nix-shell` with a path.
|
||||
E.g. `nix-shell ./update-scripts`.
|
||||
|
||||
## Explanation
|
||||
|
||||
These packages are not in the flake outputs for two main reasons:
|
||||
- Packages built using the flake must follow the flake's `nixConfig`
|
||||
- Packages included in the flake's output are checked by `nix flake check`
|
||||
|
||||
Being unable to bypass `nixConfig` is an issue because we want to disable [IFD] for the flake, but not for these generate scripts.
|
||||
|
||||
If something changes upstream that causes the builds to fail, we don't want this to block us updating `flake.lock`.
|
||||
We'd still be made aware of any issues by the `update` CI workflow failing.
|
||||
|
||||
[IFD]: https://nixos.org/manual/nix/stable/language/import-from-derivation
|
29
update-scripts/default.nix
Normal file
29
update-scripts/default.nix
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
# By default, import nixpkgs from flake.lock
|
||||
pkgs ?
|
||||
let
|
||||
lock = (builtins.fromJSON (builtins.readFile ../flake.lock)).nodes.nixpkgs.locked;
|
||||
nixpkgs = fetchTarball {
|
||||
url =
|
||||
assert lock.type == "github";
|
||||
"https://github.com/${lock.owner}/${lock.repo}/archive/${lock.rev}.tar.gz";
|
||||
sha256 = lock.narHash;
|
||||
};
|
||||
in
|
||||
import nixpkgs { },
|
||||
lib ? pkgs.lib,
|
||||
...
|
||||
}:
|
||||
lib.fix (self: {
|
||||
# The main script
|
||||
default = self.generate;
|
||||
generate = lib.callPackageWith (pkgs // self) ./generate.nix { };
|
||||
|
||||
# A shell that has the generate script
|
||||
shell = pkgs.mkShell { nativeBuildInputs = [ self.generate ]; };
|
||||
|
||||
# Derivations that build the generated files
|
||||
efmls-configs-sources = pkgs.callPackage ./efmls-configs.nix { };
|
||||
none-ls-builtins = pkgs.callPackage ./none-ls.nix { };
|
||||
rust-analyzer-options = pkgs.callPackage ./rust-analyzer.nix { };
|
||||
})
|
54
update-scripts/efmls-configs.nix
Normal file
54
update-scripts/efmls-configs.nix
Normal file
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
lib,
|
||||
vimPlugins,
|
||||
writeText,
|
||||
}:
|
||||
let
|
||||
tools = lib.trivial.importJSON "${vimPlugins.efmls-configs-nvim.src}/doc/supported-list.json";
|
||||
languages = lib.attrNames tools;
|
||||
|
||||
toLangTools' = lang: kind: lib.map (lib.getAttr "name") (tools.${lang}.${kind} or [ ]);
|
||||
|
||||
miscLinters = toLangTools' "misc" "linters";
|
||||
miscFormatters = toLangTools' "misc" "formatters";
|
||||
|
||||
sources =
|
||||
(lib.listToAttrs (
|
||||
lib.map (
|
||||
lang:
|
||||
let
|
||||
toLangTools = toLangTools' lang;
|
||||
in
|
||||
{
|
||||
name = lang;
|
||||
value = {
|
||||
linter = {
|
||||
inherit lang;
|
||||
possible = (toLangTools "linters") ++ miscLinters;
|
||||
};
|
||||
formatter = {
|
||||
inherit lang;
|
||||
possible = (toLangTools "formatters") ++ miscFormatters;
|
||||
};
|
||||
};
|
||||
}
|
||||
) languages
|
||||
))
|
||||
// {
|
||||
all = {
|
||||
linter = {
|
||||
lang = "all languages";
|
||||
possible = miscLinters;
|
||||
};
|
||||
formatter = {
|
||||
lang = "all languages";
|
||||
possible = miscFormatters;
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
writeText "efmls-configs-sources.nix" (
|
||||
"# WARNING: DO NOT EDIT\n"
|
||||
+ "# This file is generated with packages.<system>.efmls-configs-sources, which is run automatically by CI\n"
|
||||
+ (lib.generators.toPretty { } sources)
|
||||
)
|
79
update-scripts/generate.nix
Normal file
79
update-scripts/generate.nix
Normal file
|
@ -0,0 +1,79 @@
|
|||
{
|
||||
writeShellApplication,
|
||||
rust-analyzer-options,
|
||||
efmls-configs-sources,
|
||||
none-ls-builtins,
|
||||
nixfmt-rfc-style,
|
||||
}:
|
||||
writeShellApplication {
|
||||
name = "generate";
|
||||
|
||||
runtimeInputs = [ nixfmt-rfc-style ];
|
||||
|
||||
text = ''
|
||||
repo_root=$(git rev-parse --show-toplevel)
|
||||
generated_dir=$repo_root/generated
|
||||
|
||||
commit=
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--commit) commit=1
|
||||
;;
|
||||
--*) echo "unknown option $1"
|
||||
;;
|
||||
*) echo "unexpected argument $1"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
generate() {
|
||||
echo "$2"
|
||||
cp "$1" "$generated_dir/$2.nix"
|
||||
nixfmt "$generated_dir/$2.nix"
|
||||
}
|
||||
|
||||
mkdir -p "$generated_dir"
|
||||
generate "${rust-analyzer-options}" "rust-analyzer"
|
||||
generate "${efmls-configs-sources}" "efmls-configs"
|
||||
generate "${none-ls-builtins}" "none-ls"
|
||||
|
||||
if [ -n "$commit" ]; then
|
||||
cd "$generated_dir"
|
||||
git add .
|
||||
|
||||
# Construct a msg body from `git status -- .`
|
||||
body=$(
|
||||
git status \
|
||||
--short \
|
||||
--ignored=no \
|
||||
--untracked-files=no \
|
||||
--no-ahead-behind \
|
||||
-- . \
|
||||
| sed \
|
||||
-e 's/^\s*\([A-Z]\)\s*/\1 /' \
|
||||
-e 's/^A/Added/' \
|
||||
-e 's/^M/Updated/' \
|
||||
-e 's/^R/Renamed/' \
|
||||
-e 's/^D/Removed/' \
|
||||
-e 's/^/- /'
|
||||
)
|
||||
|
||||
# Construct the commit message based on the body
|
||||
# NOTE: Can't use `wc -l` due to how `echo` pipes its output
|
||||
count=$(echo -n "$body" | awk 'END {print NR}')
|
||||
if [ "$count" -gt 1 ] || [ ''${#body} -gt 50 ]; then
|
||||
msg=$(echo -e "generated: Update\n\n$body")
|
||||
else
|
||||
msg="generated:''${body:1}"
|
||||
fi
|
||||
|
||||
# Commit if there are changes
|
||||
if [ "$count" -gt 0 ]; then
|
||||
echo "Committing $count changes..."
|
||||
echo "$msg"
|
||||
git commit -m "$msg" --no-verify
|
||||
fi
|
||||
fi
|
||||
'';
|
||||
}
|
14
update-scripts/none-ls.nix
Normal file
14
update-scripts/none-ls.nix
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
vimPlugins,
|
||||
lib,
|
||||
writeText,
|
||||
}:
|
||||
let
|
||||
builtinSources = lib.trivial.importJSON "${vimPlugins.none-ls-nvim.src}/doc/builtins.json";
|
||||
builtinSourceNames = lib.mapAttrs (_: lib.attrNames) builtinSources;
|
||||
in
|
||||
writeText "none-ls-sources.nix" (
|
||||
"# WARNING: DO NOT EDIT\n"
|
||||
+ "# This file is generated with packages.<system>.none-ls-builtins, which is run automatically by CI\n"
|
||||
+ (lib.generators.toPretty { } builtinSourceNames)
|
||||
)
|
195
update-scripts/rust-analyzer.nix
Normal file
195
update-scripts/rust-analyzer.nix
Normal file
|
@ -0,0 +1,195 @@
|
|||
#
|
||||
# This derivation creates a Nix file that describes the Nix module that needs to be instantiated
|
||||
#
|
||||
# The create file is of the form:
|
||||
#
|
||||
# {
|
||||
# "<rust-analyzer.option.name>" = {
|
||||
# description = "<option description>";
|
||||
# type = {
|
||||
# kind = "<name of the type>";
|
||||
# # Other values depending on the kind, like values for enum or subTypes for oneOf
|
||||
# };
|
||||
# };
|
||||
# }
|
||||
#
|
||||
{
|
||||
lib,
|
||||
rust-analyzer,
|
||||
writeText,
|
||||
}:
|
||||
let
|
||||
packageJSON = "${rust-analyzer.src}/editors/code/package.json";
|
||||
options = (lib.importJSON packageJSON).contributes.configuration;
|
||||
|
||||
generatedStart = lib.lists.findFirstIndex (
|
||||
e: e == { title = "$generated-start"; }
|
||||
) (throw "missing generated start") options;
|
||||
generatedEnd = lib.lists.findFirstIndex (
|
||||
e: e == { title = "$generated-end"; }
|
||||
) (throw "missing generated end") options;
|
||||
|
||||
# Extract only the generated properties, removing vscode specific options
|
||||
rustAnalyzerProperties = lib.lists.sublist (generatedStart + 1) (
|
||||
generatedEnd - generatedStart - 1
|
||||
) options;
|
||||
|
||||
mkRustAnalyzerOptionType =
|
||||
nullable: property_name:
|
||||
{
|
||||
type,
|
||||
enum ? null,
|
||||
minimum ? null,
|
||||
maximum ? null,
|
||||
items ? null,
|
||||
anyOf ? null,
|
||||
# Not used in the function, but anyOf values contain it
|
||||
enumDescriptions ? null,
|
||||
}@property:
|
||||
if enum != null then
|
||||
{
|
||||
kind = "enum";
|
||||
values = enum;
|
||||
}
|
||||
else if anyOf != null then
|
||||
let
|
||||
possibleTypes = lib.filter (sub: !(sub.type == "null" && nullable)) anyOf;
|
||||
in
|
||||
{
|
||||
kind = "oneOf";
|
||||
subTypes = builtins.map (
|
||||
t: mkRustAnalyzerOptionType nullable "${property_name}-sub" t
|
||||
) possibleTypes;
|
||||
}
|
||||
else if lib.isList type then
|
||||
(
|
||||
if lib.head type == "null" then
|
||||
assert lib.assertMsg (
|
||||
lib.length type == 2
|
||||
) "Lists starting with null are assumed to mean nullOr, so length 2";
|
||||
let
|
||||
innerType = property // {
|
||||
type = lib.elemAt type 1;
|
||||
};
|
||||
inner = mkRustAnalyzerOptionType nullable "${property_name}-inner" innerType;
|
||||
in
|
||||
assert lib.assertMsg nullable "nullOr types are not yet handled";
|
||||
inner
|
||||
else
|
||||
let
|
||||
innerTypes = builtins.map (
|
||||
t: mkRustAnalyzerOptionType nullable "${property_name}-inner" (property // { type = t; })
|
||||
) type;
|
||||
in
|
||||
{
|
||||
kind = "oneOf";
|
||||
subTypes = innerTypes;
|
||||
}
|
||||
)
|
||||
else if type == "array" then
|
||||
{
|
||||
kind = "list";
|
||||
item = mkRustAnalyzerOptionType false "${property_name}-item" items;
|
||||
}
|
||||
else if type == "number" || type == "integer" then
|
||||
{
|
||||
kind = type;
|
||||
inherit minimum maximum;
|
||||
}
|
||||
else if
|
||||
lib.elem type [
|
||||
"object"
|
||||
"string"
|
||||
"boolean"
|
||||
]
|
||||
then
|
||||
{ kind = type; }
|
||||
else
|
||||
throw "Unhandled value in ${property_name}: ${lib.generators.toPretty { } property}";
|
||||
|
||||
mkRustAnalyzerOption =
|
||||
property_name:
|
||||
{
|
||||
# List all possible values so that we are sure no new values are introduced
|
||||
default,
|
||||
markdownDescription,
|
||||
enum ? null,
|
||||
enumDescriptions ? null,
|
||||
anyOf ? null,
|
||||
minimum ? null,
|
||||
maximum ? null,
|
||||
items ? null,
|
||||
# TODO: add this in the documentation ?
|
||||
uniqueItems ? null,
|
||||
type ? null,
|
||||
}:
|
||||
let
|
||||
enumDesc =
|
||||
values: descriptions:
|
||||
let
|
||||
valueDesc = builtins.map ({ fst, snd }: ''- ${fst}: ${snd}'') (
|
||||
lib.lists.zipLists values descriptions
|
||||
);
|
||||
in
|
||||
''
|
||||
${markdownDescription}
|
||||
|
||||
Values:
|
||||
${builtins.concatStringsSep "\n" valueDesc}
|
||||
'';
|
||||
in
|
||||
{
|
||||
type = mkRustAnalyzerOptionType true property_name {
|
||||
inherit
|
||||
type
|
||||
enum
|
||||
minimum
|
||||
maximum
|
||||
items
|
||||
anyOf
|
||||
enumDescriptions
|
||||
;
|
||||
};
|
||||
pluginDefault = default;
|
||||
description =
|
||||
if
|
||||
enum == null && (anyOf == null || builtins.all (subProp: !(lib.hasAttr "enum" subProp)) anyOf)
|
||||
then
|
||||
''
|
||||
${markdownDescription}
|
||||
''
|
||||
else if enum != null then
|
||||
assert lib.assertMsg (anyOf == null) "enum + anyOf types are not yet handled";
|
||||
enumDesc enum enumDescriptions
|
||||
else
|
||||
let
|
||||
subEnums = lib.filter (lib.hasAttr "enum") anyOf;
|
||||
subEnum =
|
||||
assert lib.assertMsg (
|
||||
lib.length subEnums == 1
|
||||
) "anyOf types may currently only contain a single enum";
|
||||
lib.head subEnums;
|
||||
in
|
||||
enumDesc subEnum.enum subEnum.enumDescriptions;
|
||||
};
|
||||
|
||||
rustAnalyzerOptions = builtins.map (
|
||||
v:
|
||||
let
|
||||
props = lib.attrsToList v.properties;
|
||||
prop =
|
||||
assert lib.assertMsg (
|
||||
lib.length props == 1
|
||||
) "Rust analyzer configuration items are only supported with a single element";
|
||||
lib.head props;
|
||||
in
|
||||
{
|
||||
"${prop.name}" = mkRustAnalyzerOption prop.name prop.value;
|
||||
}
|
||||
) rustAnalyzerProperties;
|
||||
in
|
||||
writeText "rust-analyzer-options.nix" (
|
||||
"# WARNING: DO NOT EDIT\n"
|
||||
+ "# This file is generated with packages.<system>.rust-analyzer-options, which is run automatically by CI\n"
|
||||
+ (lib.generators.toPretty { } (lib.mergeAttrsList rustAnalyzerOptions))
|
||||
)
|
4
update-scripts/shell.nix
Normal file
4
update-scripts/shell.nix
Normal file
|
@ -0,0 +1,4 @@
|
|||
let
|
||||
packages = import ./. { };
|
||||
in
|
||||
packages.shell
|
Loading…
Add table
Add a link
Reference in a new issue