-
Notifications
You must be signed in to change notification settings - Fork 21
Description
My problem is solved; my script is run; my Windows lnks are converted. There is no fire to put out, but I'm a bit ashamed of how I did it, and I wonder if there is a better way than I found to get the whole target value of the lnk_file object.
Mine is a simple use case. I only have links to other files and directories on my local filesystem, and there are no commands or flags to open them with,
I first tried combining the string_data.working_directory() and string_data.relative_path() methods. This has some wrinkles with . or .. terms in the middle, but pathlib.Path().resolve() could tidy those up. More fatal were at least one case where the lnk pointed to a directory; the relative_path() was simply "./DirName" and the working_directory() was None.
Then I tried an approach based on lnk_file.targets.primary_name(). This got me most of the way there, except that I could not get the initial root slash or the Windows volume letter at the beginning of the path. Those two elements in the targets don't have primary_name() methods.
I stuck with that though, and hacked up something in the except clause leaning on _raw_target.
def get_target(self) -> Path | None:
"""Get target from Windows lnk via targets.
The constituents of the lnk_file.targets property do not have
a property_name method in the case of the root_folder and the
my_computer types. This means that the initial / and the drive
letter are not accessible cleanly this way, so we descend into
hackery then.
"""
def get_primary_name(target):
"""Get primary name of target."""
try:
return target.primary_name()
except AttributeError:
# Return slash if target is root_folder.
# Yes, my_computer starts with a slash too. It is needed
# here as well. When Path is done with it, it's three.
return_value = '/'
# my_computer._raw_target starts with "/D:", etc.
if chr(target._raw_target[0]) == '/':
return_value = target._raw_target[:3].decode(UTF8)
return return_value
target = None
if self.lnk.targets is not None:
target = Path('/'.join(get_primary_name(target)
for target in self.lnk.targets))
return targetThat self.lnk part is set thusly:
def read_windows_lnk(self) -> LnkParse3.lnk_file:
"""Read Windows lnk file with LnkParse3."""
with open(self.windows_file, "rb") as win:
return LnkParse3.lnk_file(win)So, yeah, yuck. Still, that was the best I could find. Is there something better that I'm not seeing?