# if evaluating outside of the store, copy the current directory to the store and import it
# filtering out .gitignore files and .git directories
# if evaluating inside the store, import the outputs.nix file

let
  contains = str: substr: let
    str_length = builtins.stringLength str;
    substr_length = builtins.stringLength substr;
    listOfPossibleSubstrings = builtins.genList (i: builtins.substring i substr_length str) (str_length - substr_length + 1);
  in if substr_length > str_length then false else builtins.any (x: x == substr) listOfPossibleSubstrings;

  endsWith = str: substr: let
    str_length = builtins.stringLength str;
    substr_length = builtins.stringLength substr;
  in if substr_length > str_length then false else builtins.substring (str_length - substr_length) str_length str == substr;

  gitignore = builtins.filter (v:
      # ignore comments and empty lines
      if !(builtins.isString v) then false
      else if !builtins.isNull(builtins.match "^#.*" v) then false
      else if !builtins.isNull(builtins.match "^$" v) then false
      else true
    ) (builtins.split "\n" (builtins.readFile ./.gitignore));
  
  # checks if a given path matches a gitignore pattern
  # string -> bool
  matchesGitIgnore = path: builtins.any (pattern:
    let
      patternLength = builtins.stringLength pattern;
      unsupportedPatternMessage = "matchesGitIgnore: Unsupported pattern: ${pattern}";
    in
      if pattern == "*" then true
      else if pattern == ".*" then true
      else if pattern == "*.*" then true
      else if builtins.substring 0 2 pattern == "*." then endsWith path (builtins.substring 0 2 pattern)
      else if contains pattern "*" then abort unsupportedPatternMessage
      else if patternLength > 2 && builtins.substring 0 2 pattern == "./" then abort unsupportedPatternMessage
      else if patternLength > 1 && builtins.substring 0 1 pattern == "/" then abort unsupportedPatternMessage
      else contains path pattern
  ) gitignore;

  currentFilePath = (builtins.unsafeGetAttrPos "any" { any = "any"; }).file;
  storePathLength = builtins.stringLength (builtins.toString builtins.storeDir);
  evaluatingInStore = (builtins.substring 0 storePathLength currentFilePath) == builtins.storeDir;

  selfInStore = builtins.filterSource (path: type:
      type != "unknown" && builtins.baseNameOf path != ".git" && !matchesGitIgnore path
    ) ./.;
in
if !(evaluatingInStore) then { ... }@args: import selfInStore ({ selfPath = selfInStore; } // args )
else { ... }@args: import ./outputs.nix ({ selfPath = selfInStore; } // args)