diff --git a/.github/workflows/import-to-elasticsearch.yml b/.github/workflows/import-to-elasticsearch.yml index 122a0d3..f2ccaab 100644 --- a/.github/workflows/import-to-elasticsearch.yml +++ b/.github/workflows/import-to-elasticsearch.yml @@ -7,15 +7,36 @@ on: jobs: + nixos-channels: + runs-on: ubuntu-latest + + outputs: + matrix: ${{ steps.nixos-channels.outputs.matrix }} + + steps: + - name: Checking out the repository + uses: actions/checkout@v3 + + - name: Setup + uses: ./.github/actions/common-setup + with: + CACHIX_SIGNING_KEY: ${{ secrets.CACHIX_SIGNING_KEY }} + + - name: NixOS Channels + id: nixos-channels + run: | + nix build -L .#nixosChannels + channels="{\"channel\": $(< ./result)}" + echo $channels + echo "::set-output name=matrix::$channels" + import-nixpkgs: + needs: nixos-channels runs-on: ubuntu-latest strategy: fail-fast: false - matrix: - channel: - - unstable - - 21.11 + matrix: ${{ fromJSON(needs.nixos-channels.outputs.matrix) }} env: RUST_LOG: debug @@ -46,7 +67,6 @@ jobs: if: github.repository_owner == 'NixOS' - import-flakes: runs-on: ubuntu-latest diff --git a/VERSION b/VERSION index f04c001..64bb6b7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -29 +30 diff --git a/flake-info/default.nix b/flake-info/default.nix index 3d381cc..6f671b2 100644 --- a/flake-info/default.nix +++ b/flake-info/default.nix @@ -1,5 +1,7 @@ -{ pkgs ? import { } }: with pkgs; -rustPlatform.buildRustPackage rec { +{ pkgs ? import {} +, nixosChannels ? {} +}: +pkgs.rustPlatform.buildRustPackage rec { name = "flake-info"; src = ./.; cargoLock = { @@ -8,11 +10,18 @@ rustPlatform.buildRustPackage rec { "elasticsearch-8.0.0-alpha.1" = "sha256-gjmk3Q3LTAvLhzQ+k1knSp1HBwtqNiubjXNnLy/cS5M="; }; }; - nativeBuildInputs = [ pkg-config ]; - buildInputs = [ openssl openssl.dev makeWrapper ] - ++ lib.optional pkgs.stdenv.isDarwin [ libiconv darwin.apple_sdk.frameworks.Security ]; + nativeBuildInputs = with pkgs; [ pkg-config ]; + buildInputs = + with pkgs; [ + openssl + openssl.dev + makeWrapper + ] ++ lib.optional pkgs.stdenv.isDarwin [ + libiconv + darwin.apple_sdk.frameworks.Security + ]; - checkInputs = [ pandoc ]; + checkInputs = with pkgs; [ pandoc ]; NIXPKGS_PANDOC_FILTERS_PATH = "${pkgs.path + "/doc/build-aux/pandoc-filters"}"; @@ -24,6 +33,7 @@ rustPlatform.buildRustPackage rec { postInstall = '' wrapProgram $out/bin/flake-info \ --set NIXPKGS_PANDOC_FILTERS_PATH "${NIXPKGS_PANDOC_FILTERS_PATH}" \ - --prefix PATH : ${pandoc}/bin + --set NIXOS_CHANNELS '${builtins.toJSON nixosChannels}' \ + --prefix PATH : ${pkgs.pandoc}/bin ''; } diff --git a/flake-info/src/bin/flake-info.rs b/flake-info/src/bin/flake-info.rs index 9350548..55c0f36 100644 --- a/flake-info/src/bin/flake-info.rs +++ b/flake-info/src/bin/flake-info.rs @@ -5,11 +5,14 @@ use flake_info::data::import::{Kind, NixOption}; use flake_info::data::{self, Export, Nixpkgs, Source}; use flake_info::elastic::{ElasticsearchError, ExistsStrategy}; use flake_info::{commands, elastic}; +use lazy_static::lazy_static; use log::{debug, error, info, warn}; use semver::VersionReq; +use serde::Deserialize; use sha2::Digest; use std::path::{Path, PathBuf}; use std::ptr::hash; +use std::str::FromStr; use std::{fs, io}; use structopt::{clap::ArgGroup, StructOpt}; use thiserror::Error; @@ -198,6 +201,9 @@ enum FlakeInfoError { #[error("Nix check failed: {0}")] NixCheck(#[from] NixCheckError), + #[error("Nixos Channel `{0}` not among the allowed Channels set by NIXOS_CHANNELS ({:?}", .1.channels)] + UnknownNixOSChannel(String, NixosChannels), + #[error("Getting flake info caused an error: {0:?}")] Flake(anyhow::Error), #[error("Getting nixpkgs info caused an error: {0:?}")] @@ -237,6 +243,8 @@ async fn run_command( Ok((exports, ident)) } Command::Nixpkgs { channel } => { + NIXOS_CHANNELS.check_channel(&channel)?; + let nixpkgs = Source::nixpkgs(channel) .await .map_err(FlakeInfoError::Nixpkgs)?; @@ -251,6 +259,8 @@ async fn run_command( Ok((exports, ident)) } Command::NixpkgsArchive { source, channel } => { + NIXOS_CHANNELS.check_channel(&channel)?; + let ident = ( "nixos".to_string(), channel.to_owned(), @@ -404,3 +414,36 @@ async fn push_to_elastic( Ok(()) } + +/// Information about allowed and default nixos channels. +/// Typyically passed by environment variable NIXOS_CHANNELS. +/// Used to filter the input arguments for `flake-info nixpkgs` and `flake-info nixpkgs-archive` +#[derive(Clone, Debug, Deserialize)] +struct NixosChannels { + channels: Vec, +} + +#[derive(Clone, Debug, Deserialize)] +struct Channel { + branch: String +} + +impl NixosChannels { + fn check_channel(&self, channel: &String) -> Result<(), FlakeInfoError> { + self.channels.iter().find(|c| &c.branch == channel).map_or_else(|| Ok(()), |_| Err(FlakeInfoError::UnknownNixOSChannel(channel.clone(), self.clone()))) + } +} + +impl FromStr for NixosChannels { + type Err=serde_json::Error; + + fn from_str(s: &str) -> Result { + serde_json::from_str(s) + } +} + +lazy_static! { + static ref NIXOS_CHANNELS: NixosChannels = std::env::var("NIXOS_CHANNELS") + .unwrap_or("".to_string()) + .parse().unwrap(); +} diff --git a/flake.lock b/flake.lock index 4dfb84a..1e92aad 100644 --- a/flake.lock +++ b/flake.lock @@ -15,6 +15,22 @@ "type": "github" } }, + "nixos-org-configurations": { + "flake": false, + "locked": { + "lastModified": 1648674978, + "narHash": "sha256-7lVlPb9/Lu3M9xPzwdvtgqkeQI4FAMv+T3v+yT54ZZ0=", + "owner": "NixOS", + "repo": "nixos-org-configurations", + "rev": "76c0687ac275235142dae7c855aab2885302298c", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixos-org-configurations", + "type": "github" + } + }, "nixpkgs": { "locked": { "lastModified": 1650701402, @@ -33,6 +49,7 @@ "root": { "inputs": { "flake-utils": "flake-utils", + "nixos-org-configurations": "nixos-org-configurations", "nixpkgs": "nixpkgs" } } diff --git a/flake.nix b/flake.nix index 00f90eb..b3441b2 100644 --- a/flake.nix +++ b/flake.nix @@ -6,33 +6,116 @@ inputs.nixpkgs.url = "nixpkgs/nixos-unstable"; inputs.flake-utils.url = "github:numtide/flake-utils"; + inputs.nixos-org-configurations.url = "github:NixOS/nixos-org-configurations"; + inputs.nixos-org-configurations.flake = false; outputs = { self , nixpkgs , flake-utils + , nixos-org-configurations }: - flake-utils.lib.eachSystem - (with flake-utils.lib.system; [ - x86_64-linux - i686-linux - x86_64-darwin - aarch64-linux - ]) + flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; - warnToUpgradeNix = pkgs.lib.warn "Please upgrade Nix to 2.7 or later."; + lib = nixpkgs.lib; + warnToUpgradeNix = lib.warn "Please upgrade Nix to 2.7 or later."; + version = lib.fileContents ./VERSION; + nixosChannels = + let + allChannels = (import "${nixos-org-configurations}/channels.nix").channels; + filteredChannels = + lib.filterAttrs + (n: v: + builtins.elem v.status ["beta" "stable" "rolling"] && + lib.hasPrefix "nixos-" n && + v ? variant && v.variant == "primary" + ) + allChannels; + in + { + channels = + lib.mapAttrsToList + (n: v: + { + id = lib.removePrefix "nixos-" n; + status = v.status; + jobset = + builtins.concatStringsSep + "/" + (lib.init (lib.splitString "/" v.job)); + branch = n; + } + ) + filteredChannels; + default = + builtins.head + (builtins.sort (e1: e2: ! (builtins.lessThan e1 e2)) + (builtins.map + (lib.removePrefix "nixos-") + (builtins.attrNames + (lib.filterAttrs (_: v: v.status == "stable") filteredChannels) + ) + ) + ); + }; + nixosChannelsFile = pkgs.runCommand "nixosChannels.json" {} '' + echo '${builtins.toJSON (builtins.map (c: c.id) nixosChannels.channels)}' > $out + ''; + + mkDevShell = { inputsFrom ? [], extraPackages ? [], extraShellHook ? "" }: + pkgs.mkShell { + inherit inputsFrom; + packages = extraPackages; + shellHook = '' + export NIXOS_CHANNELS='${builtins.toJSON nixosChannels}'; + export ELASTICSEARCH_MAPPING_SCHEMA_VERSION="${version}"; + '' + extraShellHook; + }; in rec { packages.default = packages.flake-info; - packages.flake-info = import ./flake-info { inherit pkgs; }; - packages.frontend = import ./frontend { inherit pkgs; }; + packages.flake-info = import ./flake-info { inherit pkgs nixosChannels; }; + packages.frontend = import ./frontend { inherit pkgs nixosChannels version; }; + packages.nixosChannels = nixosChannelsFile; - devShells.default = pkgs.mkShell { - inputsFrom = builtins.attrValues packages; - shellHook = '' + devShells.default = mkDevShell { + inputsFrom = [ + packages.flake-info + packages.frontend + ]; + extraPackages = [pkgs.rustfmt]; + extraShellHook = '' export RUST_SRC_PATH="${pkgs.rustPlatform.rustLibSrc}"; export NIXPKGS_PANDOC_FILTERS_PATH="${packages.flake-info.NIXPKGS_PANDOC_FILTERS_PATH}"; + export PATH=$PWD/frontend/node_modules/.bin:$PATH + + rm -rf frontend/node_modules + ln -sf ${packages.frontend.yarnPkg}/libexec/${(builtins.parseDrvName packages.frontend.name).name}/node_modules frontend/ + echo "========================================================" + echo "= To develop the frontend run: cd frontend && yarn dev =" + echo "========================================================" + ''; + }; + + devShells.flake-info = mkDevShell { + inputsFrom = [packages.flake-info]; + extraPackages = [pkgs.rustfmt]; + extraShellHook = '' + export RUST_SRC_PATH="${pkgs.rustPlatform.rustLibSrc}"; + export NIXPKGS_PANDOC_FILTERS_PATH="${packages.flake-info.NIXPKGS_PANDOC_FILTERS_PATH}"; + ''; + }; + + devShells.frontend = mkDevShell { + inputsFrom = [packages.frontend] ; + extraShellHook = '' + export PATH=$PWD/frontend/node_modules/.bin:$PATH + rm -rf frontend/node_modules + ln -sf ${packages.frontend.yarnPkg}/libexec/${(builtins.parseDrvName packages.frontend.name).name}/node_modules frontend/ + echo "========================================================" + echo "= To develop the frontend run: cd frontend && yarn dev =" + echo "========================================================" ''; }; diff --git a/frontend/default.nix b/frontend/default.nix index 4b5667f..ddbaf52 100644 --- a/frontend/default.nix +++ b/frontend/default.nix @@ -1,5 +1,6 @@ { pkgs ? import { } -, version ? pkgs.lib.removeSuffix "\n" (builtins.readFile ../VERSION) +, nixosChannels +, version }: let package = builtins.fromJSON (builtins.readFile ./package.json); @@ -52,6 +53,9 @@ pkgs.stdenv.mkDerivation { elm-analyse ]); + ELASTICSEARCH_MAPPING_SCHEMA_VERSION = version; + NIXOS_CHANNELS = builtins.toJSON nixosChannels; + configurePhase = pkgs.elmPackages.fetchElmDeps { elmPackages = import ./elm-srcs.nix; elmVersion = pkgs.elmPackages.elm.version; @@ -66,7 +70,6 @@ pkgs.stdenv.mkDerivation { buildPhase = '' # Yarn writes cache directories etc to $HOME. export HOME=$PWD/yarn_home - sed -i -e "s|process.env.ELASTICSEARCH_MAPPING_SCHEMA_VERSION|${version}|" src/index.js yarn prod ''; @@ -75,14 +78,6 @@ pkgs.stdenv.mkDerivation { cp -R ./dist/* $out/ cp netlify.toml $out/ ''; - shellHook = '' - rm -rf frontend/node_modules - ln -sf ${yarnPkg}/libexec/${package.name}/node_modules frontend/ - export PATH=$PWD/frontend/node_modules/.bin:$PATH - export ELASTICSEARCH_MAPPING_SCHEMA_VERSION=${version} - echo "============================" - echo "= To develop the frontend run: cd frontend && yarn dev =" - echo "============================" - ''; + passthru.yarnPkg = yarnPkg; } diff --git a/frontend/src/Main.elm b/frontend/src/Main.elm index 422a7c7..89a2b24 100644 --- a/frontend/src/Main.elm +++ b/frontend/src/Main.elm @@ -25,13 +25,20 @@ import Html.Attributes , id , src ) +import Json.Decode import Page.Flakes exposing (Model(..)) import Page.Home import Page.Options import Page.Packages import RemoteData exposing (RemoteData(..)) import Route exposing (SearchType(..)) -import Search exposing (Msg(..), defaultFlakeId) +import Search + exposing + ( Msg(..) + , NixOSChannel + , decodeNixOSChannels + , defaultFlakeId + ) import Url @@ -44,6 +51,7 @@ type alias Flags = , elasticsearchUrl : String , elasticsearchUsername : String , elasticsearchPassword : String + , nixosChannels : Json.Decode.Value } @@ -51,6 +59,8 @@ type alias Model = { navKey : Browser.Navigation.Key , route : Route.Route , elasticsearch : Search.Options + , defaultNixOSChannel : String + , nixosChannels : List NixOSChannel , page : Page } @@ -70,6 +80,14 @@ init : -> ( Model, Cmd Msg ) init flags url navKey = let + nixosChannels = + case Json.Decode.decodeValue decodeNixOSChannels flags.nixosChannels of + Ok c -> + c + + Err _ -> + { default = "", channels = [] } + model = { navKey = navKey , elasticsearch = @@ -78,6 +96,8 @@ init flags url navKey = flags.elasticsearchUrl flags.elasticsearchUsername flags.elasticsearchPassword + , defaultNixOSChannel = nixosChannels.default + , nixosChannels = nixosChannels.channels , page = NotFound , route = Route.Home } @@ -127,6 +147,7 @@ attemptQuery (( model, _ ) as pair) = , Cmd.map msg <| makeRequest model.elasticsearch + model.nixosChannels searchModel.searchType searchModel.channel (Maybe.withDefault "" searchModel.query) @@ -239,7 +260,7 @@ changeRouteTo currentModel url = _ -> Nothing in - Page.Packages.init searchArgs modelPage + Page.Packages.init searchArgs currentModel.defaultNixOSChannel currentModel.nixosChannels modelPage |> updateWith Packages PackagesMsg model |> avoidReinit |> attemptQuery @@ -254,7 +275,7 @@ changeRouteTo currentModel url = _ -> Nothing in - Page.Options.init searchArgs modelPage + Page.Options.init searchArgs currentModel.defaultNixOSChannel currentModel.nixosChannels modelPage |> updateWith Options OptionsMsg model |> avoidReinit |> attemptQuery @@ -269,7 +290,7 @@ changeRouteTo currentModel url = _ -> Nothing in - Page.Flakes.init searchArgs modelPage + Page.Flakes.init searchArgs currentModel.defaultNixOSChannel currentModel.nixosChannels modelPage |> updateWith Flakes FlakesMsg model |> avoidReinit |> attemptQuery @@ -300,19 +321,19 @@ update msg model = changeRouteTo model url ( HomeMsg subMsg, Home subModel ) -> - Page.Home.update subMsg subModel + Page.Home.update subMsg subModel model.nixosChannels |> updateWith Home HomeMsg model ( PackagesMsg subMsg, Packages subModel ) -> - Page.Packages.update model.navKey subMsg subModel + Page.Packages.update model.navKey subMsg subModel model.nixosChannels |> updateWith Packages PackagesMsg model ( OptionsMsg subMsg, Options subModel ) -> - Page.Options.update model.navKey subMsg subModel + Page.Options.update model.navKey subMsg subModel model.nixosChannels |> updateWith Options OptionsMsg model ( FlakesMsg subMsg, Flakes subModel ) -> - Page.Flakes.update model.navKey subMsg subModel + Page.Flakes.update model.navKey subMsg subModel model.nixosChannels |> updateWith Flakes FlakesMsg model ( _, _ ) -> @@ -436,13 +457,13 @@ viewPage model = div [] [ text "Welcome" ] Packages packagesModel -> - Html.map (\m -> PackagesMsg m) <| Page.Packages.view packagesModel + Html.map (\m -> PackagesMsg m) <| Page.Packages.view model.nixosChannels packagesModel Options optionsModel -> - Html.map (\m -> OptionsMsg m) <| Page.Options.view optionsModel + Html.map (\m -> OptionsMsg m) <| Page.Options.view model.nixosChannels optionsModel Flakes flakesModel -> - Html.map (\m -> FlakesMsg m) <| Page.Flakes.view flakesModel + Html.map (\m -> FlakesMsg m) <| Page.Flakes.view model.nixosChannels flakesModel diff --git a/frontend/src/Page/Flakes.elm b/frontend/src/Page/Flakes.elm index fce252f..5671921 100644 --- a/frontend/src/Page/Flakes.elm +++ b/frontend/src/Page/Flakes.elm @@ -35,6 +35,7 @@ import Route import Search exposing ( Msg(..) + , NixOSChannel , viewFlakes , viewResult , viewSearchInput @@ -50,8 +51,13 @@ type Model | PackagesModel Page.Packages.Model -init : Route.SearchArgs -> Maybe Model -> ( Model, Cmd Msg ) -init searchArgs model = +init : + Route.SearchArgs + -> String + -> List NixOSChannel + -> Maybe Model + -> ( Model, Cmd Msg ) +init searchArgs defaultNixOSChannel nixosChannels model = let -- init with respective module or with packages by default searchType = @@ -60,10 +66,14 @@ init searchArgs model = mapEitherModel m = case ( searchType, m ) of ( OptionSearch, OptionModel model_ ) -> - Tuple.mapBoth OptionModel (Cmd.map OptionsMsg) <| Page.Options.init searchArgs <| Just model_ + Tuple.mapBoth OptionModel (Cmd.map OptionsMsg) <| + Page.Options.init searchArgs defaultNixOSChannel nixosChannels <| + Just model_ ( PackageSearch, PackagesModel model_ ) -> - Tuple.mapBoth PackagesModel (Cmd.map PackagesMsg) <| Page.Packages.init searchArgs <| Just model_ + Tuple.mapBoth PackagesModel (Cmd.map PackagesMsg) <| + Page.Packages.init searchArgs defaultNixOSChannel nixosChannels <| + Just model_ _ -> default @@ -71,10 +81,12 @@ init searchArgs model = default = case searchType of PackageSearch -> - Tuple.mapBoth PackagesModel (Cmd.map PackagesMsg) <| Page.Packages.init searchArgs Nothing + Tuple.mapBoth PackagesModel (Cmd.map PackagesMsg) <| + Page.Packages.init searchArgs defaultNixOSChannel nixosChannels Nothing OptionSearch -> - Tuple.mapBoth OptionModel (Cmd.map OptionsMsg) <| Page.Options.init searchArgs Nothing + Tuple.mapBoth OptionModel (Cmd.map OptionsMsg) <| + Page.Options.init searchArgs defaultNixOSChannel nixosChannels Nothing ( newModel, newCmd ) = Maybe.withDefault default <| Maybe.map mapEitherModel model @@ -97,8 +109,9 @@ update : Browser.Navigation.Key -> Msg -> Model + -> List NixOSChannel -> ( Model, Cmd Msg ) -update navKey msg model = +update navKey msg model nixosChannels = case ( msg, model ) of ( OptionsMsg msg_, OptionModel model_ ) -> case msg_ of @@ -110,6 +123,7 @@ update navKey msg model = navKey subMsg model_ + nixosChannels in ( newModel, Cmd.map Page.Options.SearchMsg newCmd ) |> Tuple.mapBoth OptionModel (Cmd.map OptionsMsg) @@ -123,6 +137,7 @@ update navKey msg model = navKey subMsg model_ + nixosChannels in ( newModel, Cmd.map Page.Packages.SearchMsg newCmd ) |> Tuple.mapBoth PackagesModel (Cmd.map PackagesMsg) @@ -134,8 +149,11 @@ update navKey msg model = -- VIEW -view : Model -> Html Msg -view model = +view : + List NixOSChannel + -> Model + -> Html Msg +view nixosChannels model = let resultStatus result = case result of @@ -172,8 +190,8 @@ view model = ) ) [ h1 [] bodyTitle - , viewSearchInput outMsg categoryName Nothing model_.query - , viewResult outMsg Route.Flakes categoryName model_ viewSuccess viewBuckets <| + , viewSearchInput nixosChannels outMsg categoryName Nothing model_.query + , viewResult nixosChannels outMsg Route.Flakes categoryName model_ viewSuccess viewBuckets <| viewFlakes outMsg model_.channel model_.searchType ] @@ -194,6 +212,7 @@ view model = makeRequest : Search.Options + -> List NixOSChannel -> SearchType -> String -> String @@ -202,13 +221,14 @@ makeRequest : -> Maybe String -> Search.Sort -> Cmd Msg -makeRequest options searchType index_id query from size maybeBuckets sort = +makeRequest options nixosChannels searchType index_id query from size maybeBuckets sort = let cmd = case searchType of PackageSearch -> Search.makeRequest (makeRequestBody searchType query from size maybeBuckets sort) + nixosChannels index_id Page.Packages.decodeResultItemSource Page.Packages.decodeResultAggregations @@ -221,6 +241,7 @@ makeRequest options searchType index_id query from size maybeBuckets sort = OptionSearch -> Search.makeRequest (makeRequestBody searchType query from size maybeBuckets sort) + nixosChannels index_id Page.Options.decodeResultItemSource Page.Options.decodeResultAggregations diff --git a/frontend/src/Page/Home.elm b/frontend/src/Page/Home.elm index 757fd10..9d4f3a8 100644 --- a/frontend/src/Page/Home.elm +++ b/frontend/src/Page/Home.elm @@ -1,6 +1,7 @@ module Page.Home exposing (Model, Msg, init, update, view) import Html exposing (Html, div, text) +import Search exposing (NixOSChannel) @@ -24,8 +25,12 @@ type Msg = NoOp -update : Msg -> Model -> ( Model, Cmd Msg ) -update msg model = +update : + Msg + -> Model + -> List NixOSChannel + -> ( Model, Cmd Msg ) +update msg model _ = case msg of NoOp -> ( model, Cmd.none ) diff --git a/frontend/src/Page/Options.elm b/frontend/src/Page/Options.elm index 5ad75b6..4a1aace 100644 --- a/frontend/src/Page/Options.elm +++ b/frontend/src/Page/Options.elm @@ -45,7 +45,12 @@ import Http exposing (Body) import Json.Decode import Json.Decode.Pipeline import Route exposing (SearchType) -import Search exposing (Details, decodeResolvedFlake) +import Search + exposing + ( Details + , NixOSChannel + , decodeResolvedFlake + ) @@ -82,11 +87,16 @@ type alias AggregationsAll = } -init : Route.SearchArgs -> Maybe Model -> ( Model, Cmd Msg ) -init searchArgs model = +init : + Route.SearchArgs + -> String + -> List NixOSChannel + -> Maybe Model + -> ( Model, Cmd Msg ) +init searchArgs defaultNixOSChannel nixosChannels model = let ( newModel, newCmd ) = - Search.init searchArgs model + Search.init searchArgs defaultNixOSChannel nixosChannels model in ( newModel , Cmd.map SearchMsg newCmd @@ -105,8 +115,9 @@ update : Browser.Navigation.Key -> Msg -> Model + -> List NixOSChannel -> ( Model, Cmd Msg ) -update navKey msg model = +update navKey msg model nixosChannels = case msg of SearchMsg subMsg -> let @@ -116,6 +127,7 @@ update navKey msg model = navKey subMsg model + nixosChannels in ( newModel, Cmd.map SearchMsg newCmd ) @@ -124,12 +136,16 @@ update navKey msg model = -- VIEW -view : Model -> Html Msg -view model = +view : + List NixOSChannel + -> Model + -> Html Msg +view nixosChannels model = Search.view { toRoute = Route.Options, categoryName = "options" } [ text "Search more than " , strong [] [ text "10 000 options" ] ] + nixosChannels model viewSuccess viewBuckets @@ -146,26 +162,28 @@ viewBuckets _ _ = viewSuccess : - String + List NixOSChannel + -> String -> Details -> Maybe String -> List (Search.ResultItem ResultItemSource) -> Html Msg -viewSuccess channel showInstallDetails show hits = +viewSuccess nixosChannels channel showInstallDetails show hits = ul [] (List.map - (viewResultItem channel showInstallDetails show) + (viewResultItem nixosChannels channel showInstallDetails show) hits ) viewResultItem : - String + List NixOSChannel + -> String -> Details -> Maybe String -> Search.ResultItem ResultItemSource -> Html Msg -viewResultItem channel _ show item = +viewResultItem nixosChannels channel _ show item = let showHtml value = case Html.Parser.run <| String.trim value of @@ -229,7 +247,7 @@ viewResultItem channel _ show item = |> Maybe.withDefault [] ) ++ [ div [] [ text "Declared in" ] - , div [] <| findSource channel item.source + , div [] <| findSource nixosChannels channel item.source ] else @@ -283,8 +301,12 @@ viewResultItem channel _ show item = ] -findSource : String -> ResultItemSource -> List (Html a) -findSource channel source = +findSource : + List NixOSChannel + -> String + -> ResultItemSource + -> List (Html a) +findSource nixosChannels channel source = let githubUrlPrefix branch = "https://github.com/NixOS/nixpkgs/blob/" ++ branch ++ "/" @@ -297,7 +319,7 @@ findSource channel source = value asGithubLink value = - case Search.channelDetailsFromId channel of + case List.head (List.filter (\x -> x.id == channel) nixosChannels) of Just channelDetails -> a [ href <| githubUrlPrefix channelDetails.branch ++ (value |> String.replace ":" "#L") @@ -342,6 +364,7 @@ findSource channel source = makeRequest : Search.Options + -> List NixOSChannel -> SearchType -> String -> String @@ -350,9 +373,10 @@ makeRequest : -> Maybe String -> Search.Sort -> Cmd Msg -makeRequest options _ channel query from size _ sort = +makeRequest options nixosChannels _ channel query from size _ sort = Search.makeRequest (makeRequestBody query from size sort) + nixosChannels channel decodeResultItemSource decodeResultAggregations diff --git a/frontend/src/Page/Packages.elm b/frontend/src/Page/Packages.elm index d1142a6..71c85ca 100644 --- a/frontend/src/Page/Packages.elm +++ b/frontend/src/Page/Packages.elm @@ -51,6 +51,7 @@ import Route exposing (Route(..), SearchType) import Search exposing ( Details(..) + , NixOSChannel , decodeResolvedFlake , viewBucket ) @@ -162,11 +163,16 @@ initBuckets bucketsAsString = |> Maybe.withDefault emptyBuckets -init : Route.SearchArgs -> Maybe Model -> ( Model, Cmd Msg ) -init searchArgs model = +init : + Route.SearchArgs + -> String + -> List NixOSChannel + -> Maybe Model + -> ( Model, Cmd Msg ) +init searchArgs defaultNixOSChannel nixosChannels model = let ( newModel, newCmd ) = - Search.init searchArgs model + Search.init searchArgs defaultNixOSChannel nixosChannels model in ( newModel , Cmd.map SearchMsg newCmd @@ -195,8 +201,9 @@ update : Browser.Navigation.Key -> Msg -> Model + -> List NixOSChannel -> ( Model, Cmd Msg ) -update navKey msg model = +update navKey msg model nixosChannels = case msg of SearchMsg subMsg -> let @@ -206,6 +213,7 @@ update navKey msg model = navKey subMsg model + nixosChannels in ( newModel, Cmd.map SearchMsg newCmd ) @@ -214,12 +222,16 @@ update navKey msg model = -- VIEW -view : Model -> Html Msg -view model = +view : + List NixOSChannel + -> Model + -> Html Msg +view nixosChannels model = Search.view { toRoute = Route.Packages, categoryName = "packages" } [ text "Search more than " , strong [] [ text "80 000 packages" ] ] + nixosChannels model viewSuccess viewBuckets @@ -282,26 +294,28 @@ filterPlatformsBucket = viewSuccess : - String + List NixOSChannel + -> String -> Details -> Maybe String -> List (Search.ResultItem ResultItemSource) -> Html Msg -viewSuccess channel showInstallDetails show hits = +viewSuccess nixosChannels channel showInstallDetails show hits = ul [] (List.map - (viewResultItem channel showInstallDetails show) + (viewResultItem nixosChannels channel showInstallDetails show) hits ) viewResultItem : - String + List NixOSChannel + -> String -> Details -> Maybe String -> Search.ResultItem ResultItemSource -> Html Msg -viewResultItem channel showInstallDetails show item = +viewResultItem nixosChannels channel showInstallDetails show item = let optionals b l = if b then @@ -368,7 +382,7 @@ viewResultItem channel showInstallDetails show item = ) |> Maybe.withDefault [] ) - ++ renderSource item channel trapClick createShortDetailsItem createGithubUrl + ++ renderSource item nixosChannels channel trapClick createShortDetailsItem createGithubUrl ++ (let licenses = item.source.licenses @@ -450,7 +464,7 @@ viewResultItem channel showInstallDetails show item = ] showPlatform platform = - case Search.channelDetailsFromId channel of + case List.head (List.filter (\x -> x.id == channel) nixosChannels) of Just channelDetails -> let url = @@ -650,8 +664,23 @@ viewResultItem channel showInstallDetails show item = ) -renderSource : Search.ResultItem ResultItemSource -> String -> Html.Attribute Msg -> (String -> String -> Html Msg) -> (String -> String -> String) -> List (Html Msg) -renderSource item channel trapClick createShortDetailsItem createGithubUrl = +renderSource : + Search.ResultItem ResultItemSource + -> List NixOSChannel + -> String + -> Html.Attribute Msg + -> + (String + -> String + -> Html Msg + ) + -> + (String + -> String + -> String + ) + -> List (Html Msg) +renderSource item nixosChannels channel trapClick createShortDetailsItem createGithubUrl = let makeLink text url = [ li [ trapClick ] [ createShortDetailsItem text url ] ] @@ -660,7 +689,7 @@ renderSource item channel trapClick createShortDetailsItem createGithubUrl = item.source.position |> Maybe.map (\pos -> - case Search.channelDetailsFromId channel of + case List.head (List.filter (\x -> x.id == channel) nixosChannels) of Nothing -> [] @@ -684,6 +713,7 @@ renderSource item channel trapClick createShortDetailsItem createGithubUrl = makeRequest : Search.Options + -> List NixOSChannel -> SearchType -> String -> String @@ -692,9 +722,10 @@ makeRequest : -> Maybe String -> Search.Sort -> Cmd Msg -makeRequest options _ channel query from size maybeBuckets sort = +makeRequest options nixosChannels _ channel query from size maybeBuckets sort = Search.makeRequest (makeRequestBody query from size maybeBuckets sort) + nixosChannels channel decodeResultItemSource decodeResultAggregations diff --git a/frontend/src/Search.elm b/frontend/src/Search.elm index a194304..e1f8ef8 100644 --- a/frontend/src/Search.elm +++ b/frontend/src/Search.elm @@ -4,15 +4,16 @@ module Search exposing , Details(..) , Model , Msg(..) + , NixOSChannel + , NixOSChannelStatus , Options , ResultHits , ResultItem , SearchResult , Sort(..) - , channelDetailsFromId - , channels , closeButton , decodeAggregation + , decodeNixOSChannels , decodeResolvedFlake , decodeResult , defaultFlakeId @@ -153,6 +154,68 @@ type Sort | AlphabeticallyDesc +type alias NixOSChannels = + { default : String + , channels : List NixOSChannel + } + + +type alias NixOSChannel = + { id : String + , status : NixOSChannelStatus + , jobset : String + , branch : String + } + + +type NixOSChannelStatus + = Rolling + | Stable + | Beta + + +channelTitle : NixOSChannel -> String +channelTitle channel = + if channel.status == Beta + then channel.id ++ " (Beta)" + else channel.id + + +decodeNixOSChannels : Json.Decode.Decoder NixOSChannels +decodeNixOSChannels = + Json.Decode.map2 NixOSChannels + (Json.Decode.field "default" Json.Decode.string) + (Json.Decode.field "channels" (Json.Decode.list decodeNixOSChannel)) + + + +decodeNixOSChannel : Json.Decode.Decoder NixOSChannel +decodeNixOSChannel = + Json.Decode.map4 NixOSChannel + (Json.Decode.field "id" Json.Decode.string) + (Json.Decode.field "status" + (Json.Decode.string + |> Json.Decode.andThen + (\status -> + case status of + "rolling" -> + Json.Decode.succeed Rolling + + "stable" -> + Json.Decode.succeed Stable + + "beta" -> + Json.Decode.succeed Beta + + _ -> + Json.Decode.fail ("Unknown status: " ++ status) + ) + ) + ) + (Json.Decode.field "jobset" Json.Decode.string) + (Json.Decode.field "branch" Json.Decode.string) + + type alias ResolvedFlake = { type_ : String , owner : Maybe String @@ -206,9 +269,11 @@ decodeResolvedFlake = init : Route.SearchArgs + -> String + -> List NixOSChannel -> Maybe (Model a b) -> ( Model a b, Cmd (Msg a b) ) -init args maybeModel = +init args defaultNixOSChannel nixosChannels maybeModel = let getField getFn default = maybeModel @@ -216,7 +281,7 @@ init args maybeModel = |> Maybe.withDefault default modelChannel = - getField .channel defaultChannel + getField .channel defaultNixOSChannel modelFrom = getField .from 0 @@ -249,7 +314,7 @@ init args maybeModel = , showInstallDetails = Unset , searchType = Maybe.withDefault Route.PackageSearch args.type_ } - |> ensureLoading + |> ensureLoading nixosChannels , Browser.Dom.focus "search-query-input" |> Task.attempt (\_ -> NoOp) ) @@ -262,9 +327,14 @@ shouldLoad model = ensureLoading : - Model a b + List NixOSChannel -> Model a b -ensureLoading model = + -> Model a b +ensureLoading nixosChannels model = + let + channels = + List.map .id nixosChannels + in if model.query /= Nothing && model.query /= Just "" && List.member model.channel channels then { model | result = RemoteData.Loading } @@ -324,8 +394,9 @@ update : -> Browser.Navigation.Key -> Msg a b -> Model a b + -> List NixOSChannel -> ( Model a b, Cmd (Msg a b) ) -update toRoute navKey msg model = +update toRoute navKey msg model nixosChannels = case msg of NoOp -> ( model @@ -338,7 +409,7 @@ update toRoute navKey msg model = , show = Nothing , from = 0 } - |> ensureLoading + |> ensureLoading nixosChannels |> pushUrl toRoute navKey ToggleSort -> @@ -359,7 +430,7 @@ update toRoute navKey msg model = , show = Nothing , from = 0 } - |> ensureLoading + |> ensureLoading nixosChannels |> pushUrl toRoute navKey ChannelChange channel -> @@ -369,7 +440,7 @@ update toRoute navKey msg model = , buckets = Nothing , from = 0 } - |> ensureLoading + |> ensureLoading nixosChannels |> pushUrl toRoute navKey FlakeChange flake -> @@ -379,7 +450,7 @@ update toRoute navKey msg model = , buckets = Nothing , from = 0 } - |> ensureLoading + |> ensureLoading nixosChannels |> pushUrl toRoute navKey SubjectChange subject -> @@ -389,7 +460,7 @@ update toRoute navKey msg model = , buckets = Nothing , from = 0 } - |> ensureLoading + |> ensureLoading nixosChannels |> pushUrl toRoute navKey QueryInput query -> @@ -403,7 +474,7 @@ update toRoute navKey msg model = , show = Nothing , buckets = Nothing } - |> ensureLoading + |> ensureLoading nixosChannels |> pushUrl toRoute navKey QueryResponse result -> @@ -426,7 +497,7 @@ update toRoute navKey msg model = ChangePage from -> { model | from = from } - |> ensureLoading + |> ensureLoading nixosChannels |> pushUrl toRoute navKey ShowInstallDetails details -> @@ -470,123 +541,11 @@ createUrl toRoute model = -- VIEW -type Channel - = Unstable - | Release_21_11 - - -{-| TODO: we should consider using more dynamic approach here -and load channels from apis similar to what status page does --} -type alias ChannelDetails = - { id : String - , title : String - , jobset : String - , branch : String - } - - -defaultChannel : String -defaultChannel = - "21.11" - - -channelDetails : Channel -> ChannelDetails -channelDetails channel = - case channel of - Unstable -> - ChannelDetails "unstable" "unstable" "nixos/trunk-combined" "nixos-unstable" - - Release_21_11 -> - ChannelDetails "21.11" "21.11" "nixos/release-21.11" "nixos-21.11" - - -channelFromId : String -> Maybe Channel -channelFromId channel_id = - case channel_id of - "unstable" -> - Just Unstable - - "21.11" -> - Just Release_21_11 - - _ -> - Nothing - - -channelDetailsFromId : String -> Maybe ChannelDetails -channelDetailsFromId channel_id = - channelFromId channel_id - |> Maybe.map channelDetails - - -channels : List String -channels = - [ "21.11" - , "unstable" - ] - - defaultFlakeId : String defaultFlakeId = "group-manual" - --- flakeFromId : String -> Maybe Flake --- flakeFromId flake_id = --- let --- find : String -> List Flake -> Maybe Flake --- find id_ list = --- case list of --- flake :: rest -> --- if flake.id == id_ then --- Just flake --- --- else --- find id_ rest --- --- [] -> --- Nothing --- in --- find flake_id flakes --- --- --- flakeIds : List String --- flakeIds = --- List.map .id flakes --- --- --- flakes : List Flake --- flakes = --- [ { id = "latest-nixos-21.11-latest" --- , isNixpkgs = True --- , title = "Nixpkgs 21.11" --- , source = "" --- } --- , { id = "latest-nixos-21.05-latest" --- , isNixpkgs = True --- , title = "Nixpkgs 21.05" --- , source = "" --- } --- , { id = "nixos-21.09-latest" --- , isNixpkgs = True --- , title = "Nixpkgs 21.09" --- , source = "" --- } --- , { id = "latest-nixos-unstable" --- , isNixpkgs = True --- , title = "Nixpkgs Unstable" --- , source = "" --- } --- , { id = "flakes" --- , isNixpkgs = False --- , title = "Public Flakes" --- , source = "" --- } --- ] - - sortBy : List Sort sortBy = [ Relevance @@ -730,9 +689,11 @@ view : , categoryName : String } -> List (Html c) + -> List NixOSChannel -> Model a b -> - (String + (List NixOSChannel + -> String -> Details -> Maybe String -> List (ResultItem a) @@ -746,7 +707,7 @@ view : -> (Msg a b -> c) -> List (Html c) -> Html c -view { toRoute, categoryName } title model viewSuccess viewBuckets outMsg searchBuckets = +view { toRoute, categoryName } title nixosChannels model viewSuccess viewBuckets outMsg searchBuckets = let resultStatus = case model.result of @@ -773,8 +734,8 @@ view { toRoute, categoryName } title model viewSuccess viewBuckets outMsg search ) ) [ h1 [] title - , viewSearchInput outMsg categoryName (Just model.channel) model.query - , viewResult outMsg toRoute categoryName model viewSuccess viewBuckets searchBuckets + , viewSearchInput nixosChannels outMsg categoryName (Just model.channel) model.query + , viewResult nixosChannels outMsg toRoute categoryName model viewSuccess viewBuckets searchBuckets ] @@ -810,12 +771,14 @@ viewFlakes outMsg _ selectedCategory = viewResult : - (Msg a b -> c) + List NixOSChannel + -> (Msg a b -> c) -> Route.SearchRoute -> String -> Model a b -> - (String + (List NixOSChannel + -> String -> Details -> Maybe String -> List (ResultItem a) @@ -828,7 +791,7 @@ viewResult : ) -> List (Html c) -> Html c -viewResult outMsg toRoute categoryName model viewSuccess viewBuckets searchBuckets = +viewResult nixosChannels outMsg toRoute categoryName model viewSuccess viewBuckets searchBuckets = case model.result of RemoteData.NotAsked -> div [] [] @@ -855,14 +818,14 @@ viewResult outMsg toRoute categoryName model viewSuccess viewBuckets searchBucke div [ class "search-results" ] [ ul [ class "search-sidebar" ] <| List.append searchBuckets buckets , div [] - (viewResults model result viewSuccess toRoute outMsg categoryName) + (viewResults nixosChannels model result viewSuccess toRoute outMsg categoryName) ] else div [ class "search-results" ] [ ul [ class "search-sidebar" ] searchBuckets , div [] - (viewResults model result viewSuccess toRoute outMsg categoryName) + (viewResults nixosChannels model result viewSuccess toRoute outMsg categoryName) ] RemoteData.Failure error -> @@ -960,12 +923,13 @@ viewBucket title buckets searchMsgFor selectedBucket sets = viewSearchInput : - (Msg a b -> c) + List NixOSChannel + -> (Msg a b -> c) -> String -> Maybe String -> Maybe String -> Html c -viewSearchInput outMsg categoryName selectedChannel searchQuery = +viewSearchInput nixosChannels outMsg categoryName selectedChannel searchQuery = form [ onSubmit (outMsg QueryInputSubmit) , class "search-input" @@ -986,17 +950,22 @@ viewSearchInput outMsg categoryName selectedChannel searchQuery = [ text "Search" ] ] :: (selectedChannel - |> Maybe.map (\x -> [ div [] (viewChannels outMsg x) ]) + |> Maybe.map (\x -> [ div [] (viewChannels nixosChannels outMsg x) ]) |> Maybe.withDefault [] ) ) viewChannels : - (Msg a b -> c) + List NixOSChannel + -> (Msg a b -> c) -> String -> List (Html c) -viewChannels outMsg selectedChannel = +viewChannels nixosChannels outMsg selectedChannel = + let + channels = + List.map .id nixosChannels + in List.append [ div [] [ h4 [] [ text "Channel: " ] @@ -1004,23 +973,19 @@ viewChannels outMsg selectedChannel = [ class "btn-group" , attribute "data-toggle" "buttons-radio" ] - (List.filterMap - (\channelId -> - channelDetailsFromId channelId - |> Maybe.map - (\channel -> - button - [ type_ "button" - , classList - [ ( "btn", True ) - , ( "active", channel.id == selectedChannel ) - ] - , onClick <| outMsg (ChannelChange channel.id) - ] - [ text channel.title ] - ) + (List.map + (\channel -> + button + [ type_ "button" + , classList + [ ( "btn", True ) + , ( "active", channel.id == selectedChannel ) + ] + , onClick <| outMsg (ChannelChange channel.id) + ] + [ text <| channelTitle channel ] ) - channels + nixosChannels ) ] ] @@ -1037,10 +1002,12 @@ viewChannels outMsg selectedChannel = viewResults : - Model a b + List NixOSChannel + -> Model a b -> SearchResult a b -> - (String + (List NixOSChannel + -> String -> Details -> Maybe String -> List (ResultItem a) @@ -1050,7 +1017,7 @@ viewResults : -> (Msg a b -> c) -> String -> List (Html c) -viewResults model result viewSuccess _ outMsg categoryName = +viewResults nixosChannels model result viewSuccess _ outMsg categoryName = let from = String.fromInt (model.from + 1) @@ -1093,7 +1060,7 @@ viewResults model result viewSuccess _ outMsg categoryName = ) ) ] - , viewSuccess model.channel model.showInstallDetails model.show result.hits.hits + , viewSuccess nixosChannels model.channel model.showInstallDetails model.show result.hits.hits , Html.map outMsg <| viewPager model result.hits.total.value ] @@ -1379,6 +1346,7 @@ makeRequestBody query from sizeRaw sort type_ sortField otherSortFields bucketsF makeRequest : Http.Body + -> List NixOSChannel -> String -> Json.Decode.Decoder a -> Json.Decode.Decoder b @@ -1386,10 +1354,15 @@ makeRequest : -> (RemoteData.WebData (SearchResult a b) -> Msg a b) -> Maybe String -> Cmd (Msg a b) -makeRequest body channel decodeResultItemSource decodeResultAggregations options responseMsg tracker = +makeRequest body nixosChannels channel decodeResultItemSource decodeResultAggregations options responseMsg tracker = let + branch : String branch = - Maybe.map (\details -> details.branch) (channelDetailsFromId channel) |> Maybe.withDefault channel + nixosChannels + |> List.filter (\x -> x.id == channel) + |> List.head + |> Maybe.map (\x -> x.branch) + |> Maybe.withDefault channel index = "latest-" ++ String.fromInt options.mappingSchemaVersion ++ "-" ++ branch diff --git a/frontend/src/index.js b/frontend/src/index.js index f32e29a..bb9cd92 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.js @@ -6,9 +6,10 @@ const {Elm} = require('./Main'); Elm.Main.init({ flags: { - elasticsearchMappingSchemaVersion: parseInt(process.env.ELASTICSEARCH_MAPPING_SCHEMA_VERSION) || 0, + elasticsearchMappingSchemaVersion: parseInt(process.env.ELASTICSEARCH_MAPPING_SCHEMA_VERSION), elasticsearchUrl: process.env.ELASTICSEARCH_URL || 'https://nixos-search-5886075189.us-east-1.bonsaisearch.net:443', elasticsearchUsername : process.env.ELASTICSEARCH_USERNAME || 'z3ZFJ6y2mR', - elasticsearchPassword : process.env.ELASTICSEARCH_PASSWORD || 'ds8CEvALPf9pui7XG' + elasticsearchPassword : process.env.ELASTICSEARCH_PASSWORD || 'ds8CEvALPf9pui7XG', + nixosChannels : JSON.parse(process.env.NIXOS_CHANNELS) } }); diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index 9d4f485..2984773 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -27,7 +27,8 @@ var common = { }, plugins: [ new webpack.EnvironmentPlugin([ - "ELASTICSEARCH_MAPPING_SCHEMA_VERSION" + "ELASTICSEARCH_MAPPING_SCHEMA_VERSION", + "NIXOS_CHANNELS" ]), new HTMLWebpackPlugin({ // Use this template to get basic responsive meta tags