I am trying to write a PKGBUILD for the AUR right now for a github project consisting of several sub applications.
So basically the CMake file of this project just runs a make to make && make install the sub applications.
These are my build and package steps:
build() {
cd "$srcdir/$_gitname"
[[ -d build ]] && rm -r build
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=/opt/od ..
}
package() {
cd "${_gitname}/build"
sudo make all
}
My problem is now that everything works except:
makepkg -i is never asking for sudo rights during build (therefore I had to add sudo in front of the make all)
When asking for installing, makepkg does not recognize the size of the package. Therefore the package does also not uninstall when running packman -R packagename
I cannot change the CMake file though, because the project is not mine and all the different subapplications belong together and if I try make && make install them separately I get a bunch of errors that they are depending each other.
The package function cannot install into the root hierarchy. Instead, makepkg is intended to install into the pkgdir under a fakeroot, where the pkgdir replicates the actual root directory structure. See ArchWiki/Creating Packages.
You can do this by adding DESTDIR="$pkgdir/" to the make options in your package function.
When pacman is invoked on the created package, it will copy the files over into the real root hierarchy.
As an exmaple
package()
{
cd "$pkgname"
DESTDIR="$pkgdir" cmake --install out
}
This will install things to $pkgdir, and then packaged to zst file.
Related
I'm starting to play around with Snowpack. It takes a different approach from Webpack by bundling individual packages right after they're installed.
The "issue" is, when I install a package I have to first run npm install --save my-package and then I have to manually pack it with npx snowpack. The Snowpack docs mention that I can include a prepare script that would snowpack everything after running npm install but that doesn't apply to individual packages, just on a generic npm install of all dependencies in my package.json. As far as I can tell, this is the case for all npm hooks mentioned in the npm docs.
Is there any way I can automatically run a script whenever I install an individual package? The only way I can think of would be to overwrite the install script and add something to it. Are there any examples of this on GitHub or elsewhere?
Update: For clarification, I'd like to run npx snowpack every time I install a new package with --save but preferably not with --save-dev or without --save. This will never be different for any package. This will be specific to a certain repo/project, not global on my system.
It is not sufficient to run snowpack after simply running npm install as you would get by hooking into postinstall or release. Additionally, I want to make sure developers working on my project can use npm install --save newdep as they normally would and then snowpack will run. I do not want to require devs to use a custom named script.
Short answer: Unfortunately, npm does not provide any built-in feature(s) to meet your requirement.
Lifecycle hooks/scripts such as postinstall are invoked only when running the generic npm install command, and not when someone runs npm install --save <pkg_name> during the projects development phase.
Workaround: Consider customizing the logic of the npm install --save compound command by essentially overriding the npm command at the shell level.
The following solution, albeit a Bash one, describes how this custom logic can be actualized for a specific project(s). However, this solution is dependent on the following conditions:
Developers working on your project must have their the shell set to Bash when running the npm install --save compound command.
Developers working on your project will need to customize their Bash startup files, namely ~/.bashrc and possibly ~/.bash_profile.
The project directory, i.e. the project directory for which you want the custom logic to be effective, must contain a custom .bashrc file.
Bash Solution:
The following three steps are necessary to configure your project, and operating system(s), so that when a developer runs npm install --save <pkg_name> (or variations of it) the npx snowpack command is subsequently invoked.
Note: Points two and three (below) are the tasks developers need to carry out (once) to customize their Bash startup files.
The project specific .bashrc file:
Firstly create the following "project specific" .bashrc file in the root of your project directory, i.e. save it at the same level as where your projects package.json file resides:
/some/path/to/my-project/.bashrc
npm() {
local name_badge="\x1b[37;40mpostinstall\x1b[0m"
array_includes() {
local word=$1
shift
for el in "$#"; do [[ "$el" == "$word" ]] && return 0; done
}
log_warn_message() {
local cmd_name=$1 warn_badge warn_mssg
warn_badge="\x1b[30;43mWARN!\x1b[0m"
warn_mssg="${cmd_name} command not found. Cannot run npx snowpack."
echo -e "\n${name_badge} ${warn_badge} ${warn_mssg}" >&2
}
log_run_message() {
echo -e "\n${name_badge} Running pseudo postinstall hook."
}
if [[ $* == "install "* || $* == "i "* ]] && array_includes --save "$#"; then
# 1. Run the given `npm install --save ...` command.
command npm "$#"
# 2. Check whether the `npx` command exists globally.
command -v npx >/dev/null 2>&1 || {
log_warn_message npx
return 1
}
log_run_message
# 3. Run the pseudo "postinstall" command.
command npx snowpack
else
# Run all other `npm` commands as per normal.
command npm "$#"
fi
}
Note: For a better understanding of what this file does refer to the "Explanation" section below.
The ~/.bashrc file:
To make the custom logic, i.e. the npm function in the aforementioned .bashrc file, effective, it's necessary to configure Bash to read the aforementioned "project specific" .bashrc file. To configure this, add the following line of code to ~/.bashrc:
PROMPT_COMMAND='if [[ "$bashrc" != "$PWD" && "$PWD" != "$HOME" && -e .bashrc ]]; then bashrc="$PWD"; . .bashrc; fi'
Note: For a better understanding of what this line of code does refer to the "Explanation" section below.
The ~/.bash_profile file:
Typically your ~/.bash_profile contains the following line of code to load the ~/.bashrc file (or some variation of it):
if [ -f ~/.bashrc ]; then . ~/.bashrc; fi
If this is not present, then it must be added to ~/.bash_profile.
Additional info.
Setup/Configuration helpers:
Consider your developers utilizing the following two commands to aid configuration of their Bash startup files, as per the aforementioned steps two and three.
For step two, run the following command:
echo $'\n'"PROMPT_COMMAND='if [[ \"\$bashrc\" != \"\$PWD\" && \"\$PWD\" != \"\$HOME\" && -e .bashrc ]]; then bashrc=\"\$PWD\"; . .bashrc; fi'" >> ~/.bashrc
This will add the PROMPT_COMMAND=... line of code to the existing ~/.bashrc file, or create a new one if it doesn't already exist:
For step three, run the following command to append the line of code necessary in the ~/.bash_profile for loading the ~/.bashrc file:
echo $'\n'"if [ -f ~/.bashrc ]; then . ~/.bashrc; fi" >> ~/.bash_profile
Is my shell configured to Bash?
To check whether the shell is configured to Bash you can create a new session, i.e. create a new Terminal window and run:
echo $0
If it prints -bash then it's using Bash.
How do I configured my shell to Bash?
If echo $0 doesn't print -bash then you'll need to change the shell. To change it to Bash run:
chsh -s /bin/bash
Note: You'll need to create a new session for this change to become effective.
Explanation
The project specific .bashrc file:
This .bashrc file contains a shell function named npm. The body of this function contains the logic necessary to override the default npm install|i --save command.
The conditions specified in the if statement, i.e, the part that reads;
if [[ $* == "install "* || $* == "i "* ]] && array_includes --save "$#"; then
...
fi
essentially reads the $* special parameter to check whether the argument(s) passed to the npm function begin with either; install , or it's shorthand equivalent i , and whether the --save option/argument has been passed too.
To check for the existence of the --save argument we pass the $# special parameter to the array_includes function. We handle this argument differently because the position of the --save option may differ in the compound command. For instance, a user may install a package by running this;
# Example showing `--save` option at the end
npm install <pkg_name> --save
or this (or some other variation):
# Example showing `--save` option in the middle
npm i --save <pkg_name>
When the conditions specified in the if statement are met, i.e. they're true, we perform the following tasks in its body:
Run the given npm install --save ... command as-is via the line that reads:
command npm "$#"
Check whether the npx command exists globally via the part that reads:
command -v npx >/dev/null 2>&1 || {
log_warn_message npx
return 1
}
If the npx command is not available (globally) we warn the user that the npx snowpack command cannot be run, and return from the function early with an exit status of 1.
Note: My logic in this check assumes that you'll be installing npx globally. However if you're installing npm locally within your project then you'll need to change this logic. Perhaps by checking whether ./node_modules/.bin/npx exists instead. Or, you may be confident that npx command will always exists, therefore conclude that this check is unnecessary.
If the npx command exists globally we then run the pseudo "postinstall" command, i.e.
command npx snowpack
When the conditions specified in the if statement are NOT met, i.e. they're false, the user is essentially running any other npm command that is not npm install --save <pkg_name>. Therefore in the else branch we run the command as-is:
command npm "$#"
The ~/.bashrc file:
In section 5.2 Bash Variables of the "Bash Reference Manual" the PROMPT_COMMAND variable is described as follows:
PROMPT_COMMAND
If set, the value is interpreted as a command to execute before the printing of each primary prompt ($PS1).
So, this line of code (here it is again):
PROMPT_COMMAND='if [[ "$bashrc" != "$PWD" && "$PWD" != "$HOME" && -e .bashrc ]]; then bashrc="$PWD"; . .bashrc; fi'
loads the "project specific" .bashrc (if one exists), which in turn overrides the npm command with the npm function. This is what essentially provides a mechanism for overriding the npm install --save compound command for a specific project(s).
See this answer by #Cyrus for further explanation.
With newer versions of Snowpack (>=2) you can run snowpack dev and it will watch your npm_modules folder for new modules to build.
I think the best bet would be to create a new script that performs the desired action. Something along the following lines in your package.json:
{
"scripts": {
"snowpack-install" : "npm install --save && npx snowpack"
}
}
Correction
You can actually use the postinstall option in package.json. The postinstall will run "AFTER the package is installed". This would look something like the following:
{
"scripts": {
"postinstall" : "npx snowpack"
}
}
We have within a package.json build script a copy command (no we cant quickly change that).
Is there any solution we can make this work multiplatform with the same syntax easily?
I looked in several npm copy packages, but they don't transpile from windows to unix paths.
We basically need something like:
"build": "doStuff && cp -r ../folder/ /dist/"
working for windows.
Any ideas?
For a cross-platform solution consider utilizing the shx package.
Firstly cd to your project directory and run the following command to install it:
npm i -D shx
Then redefine your build script in the scripts section of your package.json as follows:
"scripts": {
"build": "doStuff && shx cp -r ../folder/ ./dist/"
}
Background:
We are using yarn in this project and we don't want to write our package.json scripts with a mix of npm/yarn commands.
I have a root directory which contains a few subfolders.
Each holds a different service.
I want to create a script in the root folder that npm install each of the services, one by one.
Question:
Do you know what would be the yarn alternative to npm install <folder>?
I'm looking for something like this psuedo command: yarn <folder>
You could use --cwd there is a git issue about this :
yarn --cwd "your/path" script
You can also use cd :
cd "your/path" && yarn script
To run yarn install on every subdirectory you can do something like:
"scripts": {
...
"install:all": "for D in */; do yarn --cwd \"${D}\"; done"
}
where
install:all is just the name of the script, you can name it whatever you please
D Is the name of the directory at the current iteration
*/ Specifies where you want to look for subdirectories. directory/*/ will list all directories inside directory/ and directory/*/*/ will list all directories two levels in.
yarn -cwd install all dependencies in the given folder
You could also run several commands, for example:
for D in */; do echo \"Installing stuff on ${D}\" && yarn --cwd \"${D}\"; done
will print "Installing stuff on your_subfolder/" on every iteration.
To run multiple commands in a single subfolder:
cd your/path && yarn && yarn some-script
I am trying to find some sudo-free solution to enable my users install and unistall my application. Using
set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/opt/${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}/")
SET(CMAKE_INSTALL_RPATH "$ENV{HOME}/${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}/")
I can direct the files to the user's home directory, and
make install
works fine. With reference to
What's the opposite of 'make install', ie. how do you uninstall a library in Linux?
I did not find any idea, which is sudo-free and is not complex for a non-system-admin person.
Is anyhow make uninstall supported by CMake?
My uninstall is quite simple: all files go in a subdirectory of the user's home. In principle, removed that new subdirectory could solve the problem. Has make install, with parameters above, any side effect, or I can write in my user's guide that the newly produced subdirectory can be removed as 'uninstall'?
If you want to add an uninstall target you can take a look to the official CMake FAQ at:
https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake
If you just want a quick way to uninstall all files, just run:
xargs rm < install_manifest.txt
install_manifest.txt file is created when you run make install.
No there is not. See in the FAQ from CMake wiki:
By default, CMake does not provide the "make uninstall" target, so you
cannot do this. We do not want "make uninstall" to remove useful files
from the system.
If you want an "uninstall" target in your project,
then nobody prevents you from providing one. You need to delete the
files listed in install_manifest.txt file. [followed by some example code]
Remove files and folders (empty only) added by make install from a cmake project:
cat install_manifest.txt | sudo xargs rm
cat install_manifest.txt | xargs -L1 dirname | sudo xargs rmdir -p
The second command will print a bunch of errors because it recursively deletes folders until it finds one that is not empty. I like seeing those errors to know which folders are left. If you want to hide these errors you can add --ignore-fail-on-non-empty to rmdir.
From the source folder:
open install_manifest.txt (created by make install)
remove all the directories/files listed
remove any remaining files you missed:
xargs rm < install_manifest.txt
remove any hidden directories/files:
$rm -rf ~/.packagename
Remove the source folder.
# make uninstall
add_custom_target("uninstall" COMMENT "Uninstall installed files")
add_custom_command(
TARGET "uninstall"
POST_BUILD
COMMENT "Uninstall files with install_manifest.txt"
COMMAND xargs rm -vf < install_manifest.txt || echo Nothing in
install_manifest.txt to be uninstalled!
)
Add this to CMakeLists.txt, then an uninstall target is made by hand.
One solution is to use packaging with CPack. In Linux, that will create a package that can be installed/uninstalled by your package manager. In Windows with the NSIS generator, you'll get an installer which also deploys uninstall.exe to your program files.
Here's a basic example of creating a debian package:
$ touch file
$ cat CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
install(FILES file DESTINATION etc)
set(CPACK_PACKAGE_NAME foo)
set(CPACK_PACKAGE_CONTACT "me <me#example.com>")
set(CPACK_GENERATOR DEB)
include(CPack)
$ cmake .
$ cpack
Then instead of make install DESTDIR=/usr/local use sudo dpkg -i foo-0.1.1-Linux.deb.
To uninstall use sudo dpkg -P foo or sudo apt purge foo.
The advantage of using a package manager over make install are numerous. Here are a few:
If you lose the source code, you can still uninstall the software.
If you dpkg -S /etc/foo, it will tell you which package "owns" this file.
If you want to install a new version of the software, you won't need to manually uninstall the previous version. It's all automatic.
You can publish the package so others can install it.
If your package deploys a file that is also owned by another package, it will fail to install. That's good because it prevents you from accidentally destroying other packages.
You have the ability to add scripts to the installation. Instead of simply copying files, you can add system users, enable serves, or perform compatibility operations on old databases during upgrade.
Well .. this question came from another one closed question that i posted here. I installed android using yaourt.. and that was ok.. it worked fine.
But, before that i was trying doing manually.. using makepkg. But it seems that it did not create any package named *.pkg.tar.xz .
After a search.. and some question for my friends.. they told me that maybe the make process had problems and, it had some silent problem that not created the *.pkg.tar.xz.
So.. what do you think.. all AUR packages necessarily create *.pkg.tar.xz file and it was a problem when i was trying to build. Or has certain packages , as android , that do not create such *.pkg.tar.xz files?
An AUR package is a PKGBUILD file with instructions to makepkg to build a package (which is a .pkg.tar.xz file), so yes, unless there is any error on the build process, all AUR packages create a .pkg.tar.xz file.
You could try downloading the PKGBUILD file and running the makepkg -si manually to check any build error. Here's an example to build and install the android-sdk package, adjust accordingly to your desired package. This should create a android-sdk-*-x86_64.pkg.tar.xz file.
cd $(mktemp -d)
wget https://aur.archlinux.org/packages/an/android-sdk/android-sdk.tar.gz
tar xzvf android-sdk.tar.gz
cd android-sdk/
makepkg -si
Used arguments to makepkg:
-s, --syncdeps Install missing dependencies with pacman
-i, --install Install package after successful build