İ love NixOS. İm researching the ways of usr/bin method. example in other linux, users copy files usr/bin to make it work and it makes file work from anywhere. So i need a script that allows me to do it.
Package whatever you need the nix way and copy the executables to $out/bin
, then install that package.
This is the nix way to do it.
edit
I might also want to add, that usually /usr/bin
should not be touched by the user but is reserved for distribution specific stuff instead, while the “local” user or administration should use /usr/local/bin
to avoid conflicts with the distribution packaging.
TY.
when i check the packages. They all include connection to github. My script is very simple and i will not make my script install from github.
Additionally
i dont know how to create a suitable package. İs there any easy to understand guide about packaging?
There is no need that src
points to GitHub or any other remote service, you can use absolute or relative pathes as well to point to the scripts location.
I noticed this after replying to one of your posts on reddit that seems to be asking the same basic question.
If you didn’t already get this figured out, I’m happy to provide more feedback here or on reddit.
I think we might be able to give clearer answers if we understand what you’re trying to accomplish and what isn’t working. For example:
- What language are the executables written in?
- Are these executables individual/unrelated scripts, or part of an application/package/project?
- What do the executables do, and when/how do you run them?
- Can we see one? Ideally the most complex one. If you have a github account you could use a gist. If not, pastebin or any similar service would work.
1- Python or Bash
2- its very short example one
import os
os.system(“notify-send İ love NixOS”)
İ wondered alternative ways to do it with scripts. Someone posted on reddit. The method that includes “with import nix…” and “writeShell…” and then he or she removed it. Actually that method works for me. But i wonder it. Why it has been removed or did i lose it.
That could be something like this;
writeScriptBin "greet-nixos" ''
#!${python3}/bin/python
import os
os.system("${libnotify}/bin/notify-send I love NixOS")
''
Though that script fails for some reason…
$ nix repl '<nixpkgs>' -L
Welcome to Nix 2.10.0pre20220610_45ebaab. Type :? for help.
Loading '<nixpkgs>'...
Added 16517 variables.
nix-repl> :b writeScriptBin "greet-nixos" ''
#!${python3}/bin/python
import os
os.system("${libnotify}/bin/notify-send I love NixOS")
''
This derivation produced the following outputs:
out -> /nix/store/2jf5azigysvj3dx5932ily58488ycz03-greet-nixos
[1 built]
$ /nix/store/2jf5azigysvj3dx5932ily58488ycz03-greet-nixos/bin/greet-nixos
Invalid number of options.
There’s usually more than one way to do things in Nix/NixOS, and it’s rarely exactly the same as you’d do it anywhere else. You are leaving out a lot of context, so it’s hard for people to know they aren’t sending you to do something that won’t work (or that will be a lot harder than doing it some other way) in your case.
For example, the code NobbZ gave above might work if your actual Python scripts don’t use any external Python modules and if you are okay with moving their contents into .nix
files. But:
-
If you are looking for another way because you want to avoid moving your script contents into
.nix
files, you’ll need a different approach than all of the examples here. -
If your actual scripts expect to find modules that you’d install globally with
pip install ...
on some other distro, you’ll need a different approach.If you do need external modules, you might need something more like what these do:
- dotfiles/overlay.nix at eeb71d6ba70771bb7118c3f9ad205fa3c5918714 · lheckemann/dotfiles · GitHub
- stockholm/cidr2glob.nix at ba6a5456e8d76b9c1eae7cd81dca3f2b16359ba2 · krebs/stockholm · GitHub
If your scripts need modules and you also expect those modules to be importable when you run
python
from a shell–you’ll need to do it a little differently.
The approach for Python and Bash will also differ (and the ideal approach depends on context and personal preference).
with import <nixpkgs> {};
writeScriptBin "QuteBrowserDiscord.py" ''
python3 /home/myusername/missionapp.py
''
İf i add
with import <nixpkgs> {};
it works. This method also need to import from configutation.nix.
@abathur yes my file is really simple
My thanks for you both. I think for now. İts sufficient but i will keep learning.
Though that script fails for some reason…
notify-send takes one (or two) positional arguments (see notify-send --help
):
$ notify-send I love NixOS
Invalid number of options.
$ notify-send "I love NixOS"
(success)
I just translated their snippet.
-
with
is an antipattern - The script looks as if it was bash, you should use
writeShellScriptBin
then to get proper shebang - If it’s indeed not bash, then you should add a proper shebang
- You should use string interpolation to get absolute pathes to runtime dependencies referenced properly by the closure
- Instead of just wrapping your python file you have elsewhere, you should package that file/project by the usual means of python packaging to get it’s runtime dependencies into the closure
Ty for helps. i can add my app to nix store now but i cant call it with terminal and i cant see it on Wofi. Also im so sry if i annoy you and waste your time. İ just wanted to learn easiest way.
@NobbZ @abathur
Once you packaged, you need to add the package to your system configuration, home-manager configuration, nix profile
/nix-env
, use it via nix-shell -p
/nix shell
or whatever else you might use to get packages into your current environment.
@NobbZ @abathur
İ used this tactic.
First typed nix repl '<nixpkgs>' -L
and then on repl
:i writeShellScriptBin "myscript" ''
notify-send i love NixOS
''
İ hope this is not antipattern or i will cry.
:i
in the REPL is similar to nix-env
/nix profile
. I am not sure which of those it uses under the hood though.
Anyway, as it is imperatively installing stuff even without leaving any traces about its origin, this can definitely considered an antipattern.
On top of that, not using string interpolation is an antipattern as well, as it requires notify-send
to be installed already.
To save you some guesswork, in /etc/nixos/configuration.nix
:
environment.systemPackages = [
# Put this in the existing list, don't make a second one
(writeShellScriptBin "myscript" ''
${pkgs.libnotify}/bin/notify-send i love NixOS
'')
];
“String interpolation” refers to the ${pkgs.libnotify}
bit; what it does is it takes whatever nix expression you put inside, and automatically turns it into a string.
In the case of a derivation (which is nix parlance for package) like libnotify, nix will turn that into the string that refers to its path in the nix store, so that will automatically turn into something like /nix/store/libnotify
, and we will run whatever is in the bin/notify-send
directory of that package.
Nix will also automatically pick up paths like that and install the dependencies for us as well, which is extremely handy, because it means we don’t need to explicitly add libnotify
to our packages.
As for what the other stuff here does, NixOS will take all derivations in environment.systemPackages
and make them usable for you. It will add all files in the bin
subdirectory of your derivation to your $PATH
, which means that you can just execute them by typing their name in your shell.
writeShellScriptBin
is a little convenient function that makes a derivation which has a bin directory, puts a file inside of it with the name you give it, and writes the contents of your second string into it. It will also add a shebang for you and make the file executable. Since that’s in the bin directory, everything is set up such that nixos will install it correctly for you to run.
You can of course use any other derivation as well, like stdenv.mkDerivation
. You just need to make the bin directory and write some other stuff yourself with those. There are lots of examples in the nixpkgs manual, and in nixpkgs itself of course (click the source link for any package you searched for using search.nixos.org and it will take you straight to how it is defined!).
Finally, regarding nix-env
, :i
and nix profile
, all of these will magically install the derivation without keeping track of it in your configuration.nix
. They will also install into either your user or root profile, depending on whether you used sudo.
All these methods will not update their packages when you use nixos-rebuild switch
, and the resulting small incompatibilities are one of the most common types of question on this discourse. I’d therefore not recommend using those commands (ever), so I won’t have to be confused at your question next year
You can list all packages you’ve previously installed using sudo nix-env -q
and nix-env -q
, and clean them up using sudo nix-env --uninstall
(for packages listed by the first command) and nix-env --uninstall
(for packages listed by the second command).
In the future, when installing anything, add it to that systemPackages
list instead, and use sudo nixos-rebuild switch
. If you start using home-manager, its version of systemPackages
is totally fine too, of course, the important part is to make sure something keeps track of this imperatively.
If you use nix on a non-NixOS distro without home-manager, nix-env
and friends become more useful.
Ok, I think that does it. @NobbZ is (as usual) very right about everything they say, but I think some detail for new users goes a long way in explaining what’s happening. Does take a lot more effort though
If anything else is unclear, happy to try my best explaining.
Good advice. Everything into the store and then just linking the binaries and as it seems, Nix want’s system binaries to be located in /bin
all the time. I don’t mind. But didn’t you mean to say linking the binary instead of copying?
I have a bunch of scripts in a git repo and I want those to be available in $PATH, but there are a bunch of files that a relatively included.
Also, fetchFromGitHub and all the other fetchers want explicit hashes, so it’s reproducable. This is not that bad, but the repo is at constant working changes for my own personal need, so I guess I should clone it manually and not rely on NixOS for this, right?
Not at all.
Package them and then add that package(s) to environment.systemPackages
or whatever else feels more appropriate for you.
As long as the scripts are within the $out/bin
and executable and the shebang/interpreter/linker is filled in correctly, it’ll just work.
Details depend of course on the implementing language.
Then you need to constantly bump your src
s hash
and rev
, alternatively tools like niv
or npins
can help you with that.
Thanks for the correction. I will look into niv and npins.