From a793c1d9938da1c7c962feff13dc948523fcc774 Mon Sep 17 00:00:00 2001
From: Eli Schwartz <eschwartz93@gmail.com>
Date: Sat, 16 Dec 2023 21:53:38 -0500
Subject: [PATCH] fix critical existence failure of install_mo

In commit d28f5fa57eef7fa9baa28dea119b45e74145ecb5 the self.root was
added, and we ended up with this directory repeated twice and bogus
installed files

When building a wheel, the value of self.root is internally implemented
by bdist_wheel as (build/bdist.linux-x86_64/wheel); the resulting wheel
placed files in random locations inside of the installed site-packages
directory.

When running `python setup.py install --root=$DESTDIR`, the value of
self.root is of course `$DESTDIR`, leading to installed files that got
installed to the staging install directory, e.g. the resulting .deb file
would attempt to install files to
```
/home/$USERNAME/projects/foobar/debian/tmp/usr/share/locale
```
during an `apt install`.

This is incorrect use of the setuptools API, as witnessed in
install_data which does the same task correctly:

```
if not os.path.isabs(dir):
    dir = os.path.join(self.install_dir, dir)
elif self.root:
    dir = change_root(self.root, dir)
```

Rather than continuing to copy-paste code around, inherit correctly from
the existing class. Update the data_files attribute of the new
install_mo implementation, and use that to drive the installation of
files using the same battle-tested logic used by `setup(data_files=[])`.

Fixes #30
---
 setuptools_gettext/__init__.py | 43 +++++++---------------------------
 1 file changed, 8 insertions(+), 35 deletions(-)

diff --git a/setuptools_gettext/__init__.py b/setuptools_gettext/__init__.py
index dc4ae73..59769b4 100644
--- a/setuptools_gettext/__init__.py
+++ b/setuptools_gettext/__init__.py
@@ -26,6 +26,7 @@
 import sys
 from typing import List, Optional, Tuple
 
+from distutils.command.install_data import install_data
 from setuptools import Command
 from setuptools.dist import Distribution
 
@@ -165,41 +166,19 @@ def run(self):
                     os.unlink(os.path.join(root, file_))
 
 
-class install_mo(Command):
+class install_mo(install_data):
 
     description: str = "install .mo files"
 
-    user_options = [
-        (
-            'install-dir=',
-            'd',
-            "base directory for installing data files "
-            "(default: installation base dir)",
-        ),
-        ('root=', None,
-         "install everything relative to this alternate root directory"),
-        ('force', 'f', "force installation (overwrite existing files)"),
-    ]
-
-    boolean_options: List[str] = ['force']
     build_dir: Optional[str]
-    install_dir: Optional[str]
-    root: Optional[str]
 
     def initialize_options(self) -> None:
-        self.install_dir = None
-        self.outfiles: List[str] = []
-        self.root = None
-        self.force = 0
+        super().initialize_options()
+        self.data_files: List[str] = []
         self.build_dir = None
 
     def finalize_options(self) -> None:
-        self.set_undefined_options(
-            'install',
-            ('install_data', 'install_dir'),
-            ('root', 'root'),
-            ('force', 'force'),
-        )
+        super().finalize_options()
         if self.build_dir is None:
             self.build_dir = (
                 self.distribution.gettext_build_dir)  # type: ignore
@@ -207,18 +186,12 @@ def finalize_options(self) -> None:
     def run(self) -> None:
         assert self.install_dir is not None
         assert self.build_dir is not None
-        self.mkpath(self.install_dir)
         import glob
         for filepath in glob.glob(self.build_dir + "/*/LC_MESSAGES/*.mo"):
             langfile = filepath[len(self.build_dir.rstrip('/')+'/'):]
-            targetpath = os.path.join(
-                self.install_dir,
-                os.path.dirname(os.path.join("share/locale", langfile)))
-            if self.root is not None:
-                targetpath = change_root(self.root, targetpath)
-            self.mkpath(targetpath)
-            (out, _) = self.copy_file(filepath, targetpath)
-            self.outfiles.append(out)
+            install_dir = os.path.dirname(os.path.join("share/locale", langfile))
+            self.data_files.append((install_dir, [filepath]))
+        super().run()
 
     def get_inputs(self):
         import glob
