electron-builder icon indicating copy to clipboard operation
electron-builder copied to clipboard

DEB build created hardlinks which breaks when /opt is on a different drive

Open rathboma opened this issue 3 years ago • 25 comments

  • Version: 22.9.1
  • Electron Version: 9.x
  • Target: DEB

If /opt is on it's own device the DEB installer throws errors when creating hardlinks:

Preparing to unpack .../beekeeper-studio_1.10.0_amd64.deb ...
Unpacking beekeeper-studio (1.10.0) over (1.9.4) ...
13dpkg: error processing archive /var/cache/apt/archives/beekeeper-studio_1.10.0
_amd64.deb (--unpack):
 error creating hard link './usr/share/icons/hicolor/24x24/apps/beekeeper-studio
.png': Invalid cross-device link
Errors were encountered while processing:
 /var/cache/apt/archives/beekeeper-studio_1.10.0_amd64.deb
E: Sub-process /usr/bin/dpkg returned an error code (1)

This is present in the app I maintain (Beekeeper Studio) and found for other electron apps hosted on GitHub:

  • https://github.com/beekeeper-studio/beekeeper-studio/issues/593
  • https://github.com/LN-Zap/zap-desktop/issues/2089

rathboma avatar Mar 19 '21 21:03 rathboma

I believe that means it's failing at this line: https://github.com/electron-userland/electron-builder/blob/da85087143d2c6a63faab4c44c28dc625326e9ee/packages/app-builder-lib/templates/linux/after-install.tpl#L4

I had a similar issue with our project in that we couldn't use symlinks either. Instead I mirrored the after-install.tpl of electron-builder and swapped out the ln line with a script.

#!/bin/bash

# Link to the binary
cat <<< '
#!/bin/bash

cd "/opt/${productFilename}/"
exec "./${executable}" "$@"
' > "/usr/bin/${executable}"
chmod 4755 "/usr/bin/${executable}"

# SUID chrome-sandbox for Electron 5+
chmod 4755 '/opt/${productFilename}/chrome-sandbox' || true

update-mime-database /usr/share/mime || true
update-desktop-database /usr/share/applications || true

Used in electron-builder as:

deb: {
    afterInstall:"path/to/your/after-install.tpl"
}

Try giving that a shot? 🙂

mmaietta avatar Mar 25 '21 02:03 mmaietta

The line mentioned by you looks OK, it's a symbolic link (-s option), not a hardlink so this part won't fail. It's something about how electron-builder links icons.

furai avatar Mar 25 '21 10:03 furai

I found this issue: https://github.com/AppImage/appimaged/issues/34 and it mentions this:

update-desktop-database ~/.local/share/applications/
update-mime-database ~/.local/share/mime/

Where are your desktop/mime databases located? I'm wondering if the assumption of /usr/share is causing this hardlink error then

mmaietta avatar Mar 25 '21 20:03 mmaietta

@mmaietta If set "productName": "破笼", chmod 4755 '/opt/${productFilename}/chrome-sandbox' || true error:

$ sudo dpkg -i po-long_1.0.1_amd64_linux.deb 
[sudo] m 的密码: 
正在选中未选择的软件包 po-long。
(正在读取数据库 ... 系统当前共安装有 249729 个文件和目录。)
准备解压 po-long_1.0.1_amd64_linux.deb  ...
正在解压 po-long (1.0.1) ...
正在设置 po-long (1.0.1) ...
chmod: 无法访问 '/opt/po-long/chrome-sandbox': 没有那个文件或目录

electron 12.0.5, electron-builder 22.10.5.

Real install path is /opt/破笼, but the script find /opt/po-long. If change electron-builder to 22.9.1, no error.

package.json:

{
  "name": "po-long",
...
  "build": {
    "appId": "red.lilu.app.pl",
    "productName": "破笼",
...
    "artifactName": "${name}_${version}_${arch}_${os}.${ext}",
    "linux": {
      "category": "Network.P2P",
      "target": [
        "deb",
        "rpm"
      ],
      "icon": "build/assets",
      "executableName": "po-long"
    },

additional:

I want to change the name of shortcut from po-long to 破笼. So i set "productName": "破笼". But it doesn't look good. The installation path and executable file name have also been modified... "executableName": "po-long" change the executable file name back to po-long, but not the installation path.

Is there any way to just change the shortcut name?

alx696 avatar Apr 25 '21 04:04 alx696

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

stale[bot] avatar Jun 26 '21 01:06 stale[bot]

I think I may be misunderstanding what you're looking for. When you mean shortcut, are you referring to what the Desktop entry shows? https://github.com/electron-userland/electron-builder/blob/28cb86bdcb6dd0b10e75a69ccd34ece6cca1d204/packages/app-builder-lib/src/targets/LinuxTargetHelper.ts#L111-L116

Can you try using this file for your afterInstall hook for Linux? This tpl file uses productFilename instead of the default sanitizedProductName which is what I think is creating your issue. Ref: Docs https://github.com/electron-userland/electron-builder/blob/28cb86bdcb6dd0b10e75a69ccd34ece6cca1d204/packages/app-builder-lib/templates/linux/after-install.tpl

mmaietta avatar Jun 28 '21 01:06 mmaietta

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

stale[bot] avatar Aug 28 '21 17:08 stale[bot]

@mmaietta so sorry I missed your response. It seems like that template always gets executed?

I have an after-install FPM hook specified for my DEB builds: --after-install=build/deb-postinstall, but I still have this issue. Do you know if there's a way to disable that script?

rathboma avatar Aug 30 '21 18:08 rathboma

For some reason, afterInstall was made explicitly available instead of through the FPM hook.

deb: {
   afterInstall: 'build/deb-postinstall'
}

mmaietta avatar Aug 31 '21 00:08 mmaietta

@mmaietta Thanks for your fix https://github.com/electron-userland/electron-builder/pull/5941/files/326873dafe3ac38b0fa2819c7f7176791c572070

package.json:

{
  "name": "polong",
...
  "build": {
    "appId": "red.lilu.app.pl",
    "productName": "破笼",
...
    "linux": {
      "category": "Network;P2P",
      "target": [
        "deb"
      ],
      "executableName": "po-long"
    }

works fine from v22.11.7.

It is better to remove update-desktop-database /usr/share/applications || true from after-install.tpl. Debian 11 KDE not install desktop-file-utils, update-desktop-database can not execute:

/var/lib/dpkg/info/polong.postinst:行10: update-desktop-database:未找到命令

It doesn't affect the use, but it doesn't look good.

or change to:

if hash update-mime-database 2>/dev/null; then
        update-mime-database /usr/share/mime
fi

if hash update-desktop-database 2>/dev/null; then
        update-desktop-database /usr/share/applications
fi

reference vscode /var/lib/dpkg/info/code.postinst

alx696 avatar Sep 02 '21 15:09 alx696

@alx696 would you be willing to open a PR for that? I always am encouraging community contributions 🙂 Setting up a local dev environment is fairly straightforward too https://github.com/electron-userland/electron-builder/blob/master/CONTRIBUTING.md#to-setup-a-local-dev-environment

mmaietta avatar Sep 02 '21 16:09 mmaietta

@mmaietta does your commit fix this issue? Should this be closed?

rathboma avatar Dec 02 '21 20:12 rathboma

Ah no, I don't think this fixes is for us as it's the assets being hard linked causing this issue:

"E:/var/cache/apt/archives/beekeeper-studio_2.1.5_amd64.deb: error creating hard link './usr/share/icons/hicolor/256x256/apps/beekeeper- studio.png':Invalid cross-device link"

rathboma avatar Dec 02 '21 20:12 rathboma

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

stale[bot] avatar Apr 16 '22 15:04 stale[bot]

Ping.

dhs-rec avatar Apr 19 '22 06:04 dhs-rec

Would it be adequate to just ignore the result of this line and echo that it failed? https://github.com/kris7t/electron-builder/blob/dc359de5019807a014c62468385dfb14bbb5bd83/packages/app-builder-lib/templates/linux/after-install.tpl#L4

Not sure if there is another way ln -sf could fail.

mmaietta avatar Apr 19 '22 07:04 mmaietta

I just ran into this whilst trying to install upscayl https://github.com/upscayl/upscayl/issues/652.

Please fix it, it should be extremely simple to fix, just create a symlink instead of a hardlink.

infinity0 avatar Feb 13 '24 13:02 infinity0

Not sure if there is another way ln -sf could fail.

This is unrelated to the bug. ln -sf cannot fail by creating instead a hardlink. Something is calling ln without the -s flag.

infinity0 avatar Feb 13 '24 13:02 infinity0

A workaround for end users that have no control over the .deb creation process, is to install the package with dpkg --path-exclude then create the symlinks manually. For example for Upscayl:

$ sudo dpkg -i \
  --path-exclude=/usr/share/icons/hicolor/512x512/apps/upscayl.png \
  --path-exclude=/usr/share/icons/hicolor/128x128/apps/upscayl.png \
  upscayl-2.9.9-linux.deb
$ sudo ln -s /opt/Upscayl/resources/128x128.png /usr/share/icons/hicolor/128x128/apps/upscayl.png
$ sudo ln -s /opt/Upscayl/resources/512x512.png /usr/share/icons/hicolor/512x512/apps/upscayl.png

infinity0 avatar Feb 13 '24 13:02 infinity0

@infinity0 I'm tackling some high-priority items already in addition to swamped with work. Please open a PR with your suggested changes and I'm happy to give it a review

mmaietta avatar Feb 13 '24 16:02 mmaietta

In the real world you can't expect unrelated strangers to fix boring bugs on your own project for free. I've reported exactly how to fix it, this is already more time than most strangers are willing to spend.

infinity0 avatar Feb 15 '24 14:02 infinity0

"In the real world" Get off your high horse. I'm the only maintainer on this project and have a life outside of this, what I do here is for free and out of care for helping others succeed at their own projects. Have a constructive mindset and conversation or don't comment at all.

I'll attend to this issue when I get around to it. Anyone is still free to open a PR with changes and I'm happy to review

mmaietta avatar Feb 15 '24 17:02 mmaietta

Update: I've created a PR targeting this issue but am struggling to set up a Parallels VM that can test this directly. I'll be continuing to investigate how to do so

If anyone is willing to try this patch via patch-package in the interim, it'd be greatly appreciated to help verify the fix. app-builder-lib+24.13.1.patch

diff --git a/node_modules/app-builder-lib/templates/linux/after-install.tpl b/node_modules/app-builder-lib/templates/linux/after-install.tpl
index 0f541f9..65e7326 100644
--- a/node_modules/app-builder-lib/templates/linux/after-install.tpl
+++ b/node_modules/app-builder-lib/templates/linux/after-install.tpl
@@ -3,9 +3,9 @@
 if type update-alternatives 2>/dev/null >&1; then
     # Remove previous link if it doesn't use update-alternatives
     if [ -L '/usr/bin/${executable}' -a -e '/usr/bin/${executable}' -a "`readlink '/usr/bin/${executable}'`" != '/etc/alternatives/${executable}' ]; then
-      rm -f '/usr/bin/${executable}'
+        rm -f '/usr/bin/${executable}'
     fi
-    update-alternatives --install '/usr/bin/${executable}' '${executable}' '/opt/${sanitizedProductName}/${executable}' 100
+    update-alternatives --install '/usr/bin/${executable}' '${executable}' '/opt/${sanitizedProductName}/${executable}' 100 || ln -sf '/opt/${sanitizedProductName}/${executable}' '/usr/bin/${executable}'
 else
     ln -sf '/opt/${sanitizedProductName}/${executable}' '/usr/bin/${executable}'
 fi
@@ -13,5 +13,10 @@ fi
 # SUID chrome-sandbox for Electron 5+
 chmod 4755 '/opt/${sanitizedProductName}/chrome-sandbox' || true
 
-update-mime-database /usr/share/mime || true
-update-desktop-database /usr/share/applications || true
+if hash update-mime-database 2>/dev/null; then
+    update-mime-database /usr/share/mime || true
+fi
+
+if hash update-desktop-database 2>/dev/null; then
+    update-desktop-database /usr/share/applications || true
+fi

From what I understand, update-alternatives is supposed to create symlinks, not hardlinks, but it's the only mention I see that is referencing /opt and that doesn't have a fallback

I've also added the change to ensure update-mime/desktop-database exists on the system before attempting to execute it.

mmaietta avatar Feb 21 '24 20:02 mmaietta

From what I understand, update-alternatives is supposed to create symlinks, not hardlinks

Furthermore, the files being hardlinked that users have reported are icons, not the binaries that are managed by update-alternatives.

Furthermore your general approach can't work because these commands are executed at build time. If builder computer has /opt on the same partition, the hardlink will succeed. But it's end-user computers that matter. There should be no attempt made to create hardlinks in the first place. forget this, seems I misinterpreted the script

You should re-open the bug. I predict other people are going to experience the same problem even with this "fix".

Have a think about what's dealing with the icons. I'm not familiar with the nodejs/electron ecosystem, and purposefully refuse to become familiar with it, it's bad for my mental health.

infinity0 avatar Mar 11 '24 16:03 infinity0

Have a think about what's dealing with the icons.

Also, the icons are created as hardlinks directly in the data portion of the deb file. In other words, this can't possibly be anything to do with post-install scripts or any other scripts being run on the end-user computer. Something is creating hardlinks on the builder computer and packaging them as hardlinks in the data portion of the deb file.

infinity0 avatar Mar 11 '24 16:03 infinity0