Best Approach—Sharing Macros That Call Common Subroutines?

Hello forum users.

For several months I've been using Keyboard Maestro macro subroutines. Use, however, has been almost exclusively limited to macros I use myself, but do not share.

For those macros that I've shared here (notwithstanding two that I recently shared: Macro Rich Link To Clipboard and Navigate to Configured Subroutine), I've kept the logic contained within a standalone macro.

As I've now built a substantial group of subroutines, I'd like to shift my approach and leverage these subroutines for the macros that I share. But as I consider this change, I have a few questions/concerns.

Suppose I have two main macros that I want to share:

  • macro main_1 that requires two subroutines

    • macro sub_A
    • macro sub_B
  • macro main_2 that requires two subroutines

    • macro sub_B
    • macro sub_C

When I share main_1, obviously I'd want to include sub_A and sub_B in the post.

Likewise when I share main_2, I'd want to include sub_B and sub_C in the post.

Now, if a user had downloaded and used main_1 (with subroutines) and later downloads and installs main_2 and subroutines, a second sub_B (with a different UUID) is installed.

Obviously, this scenario is not ideal. I'm wondering how others have managed this scenario. Off hand, I can think of two possibliites:

  • Provide instructions to users to check for existing versions of the components, and if they exist, delete them before installing the main and subs. For example, when installing main_2, advise users to first delete sub_B, sub_C, and main_2.

  • Provide an installation macro that first deletes the existing components before installing the downloaded versiosn..


Any suggestions would be greatly appreciated. Thanks!

1 Like

I can't see any good solutions to this.

The best I can think of would be to export the macros separately (one file for the macro(s) you are sharing, and one file for the common sub-macros.

Then when importing the latter, people can more easily see if there are duplicates.

It doesn't really resolve the issue though, if there is a duplicate, which version is now correct? What if changes are made to the sub-macros? What if the user is not reading an old forum post with the old sub-macros, when they already have the new sub-macros installed.

Version control is a very tricky problem.

2 Likes

Yes, it’s a thorny problem this one.

Because in the past I’ve produced a couple of complicated macro systems I started working on the second approach of yours: a system to create macro installation packages that would enable the straightforward and foolproof mechanism to distribute and install macros and their supporting files. But TBH I lost interest because of other commitments and I didn’t make much progress on it at all.

In the meantime my users have the joy of reading and following sets of instructions to install and update my complex macros which isn’t such a palaver - for me :face_with_diagonal_mouth: - until one of them doesn’t follow the instructions!

2 Likes

What works great in our own personal Macro Libraries probably has to be adapted if Macros that use Subroutines are going to be shared.

I have a single Group called "Subroutines" where I keep Subroutines that are used by other Macros in other Groups. But that is for my own use.

If I wanted to share a Macro that makes use of a Subroutine, to the Forum I would make a new Group and have both the Main Macro and the Subroutine it calls in this one Group.

I would select the Group and use File>Export>Export Macros which makes a single file with the .kmmacros extension. When this single file is downloaded, double-clicking it will install the whole self-contained Group.

The person downloading gets only one new Group added to their Library. If they decide they don't want to keep my Macros they just delete this single Group.

If I want to make updates to the Macros in the Group or add new Macros, I first duplicate ⌘D the existing Group and give this copy a higher version number. This makes a new self-contained Group with its own unique Subroutines with their unique UUIDs.

This new Group can be exported and downloaded. The previously downloaded Group is disabled/deleted. It keeps it simple and clean.

This is why there is no single answer to the question "should subroutines be kept in their own Group or in the Group of the Macros calling them?". For personal use it makes sense to have a Group called "Subroutines" and keep several subroutine Macros in there which get called by other Macros in other Groups. But for sharing I think it is better to have self-contained Groups.

2 Likes

This is seemingly very effective but…

The thing we all like about subroutines is you only need one of them and if you update it it doesn’t break anything else.

Having multiple copies of the same subroutine (if you’ve shared several macro groups containing them) suddenly makes maintenance a nightmare.

Maybe my approach would be to have a “subroutine library group” called Tiffle Subroutines and then I’d be able to share any of my macros that use those subroutines without having to take special measures - other than to say “you must install this library first to use this macro”.

As @peternlewis said - it’s very tricky.

While in no way volunteering for anything, and not having thought this through at all, two words spring to mind...

"Package manager".

You'd have to come up with your own (or set a standard for) conventions, but I can see something bare bones like "start each of your main macros with a check for a subroutine with the correct version number, and if it isn't there then download from a repo (forum link?) and walk user through install".

1 Like

I've only ever shared this one Group of Macros and it uses subroutines that are only used by it. So, I only ever have one copy (the latest copy) of the subroutines to maintain.

But for a more general subroutine (like one that inserts a date for example) I think I would still have the same approach for sharing (i.e. put a copy of the date subroutine it uses in the same Group before exporting for sharing). But I would not access this copy of the subroutine from any other Macros. I would have my own personal date subroutine in my Subroutines Group and know this is the latest one.

2 Likes

Maybe something Peter wrote in reply to one of my feature requests gives some perspective on this question:

3 Likes

Hey Guys,

I haven't seriously looked at this question vis-à-vis Keyboard Maestro, however over the nearly 30 years I've been AppleScripting and using AppleScript libraries I've run into the same sort of problem head on.

Many years ago I was regularly posting AppleScripts to the ASUL that weren't working for other users, and upon investigation I realized I wan't posting the handlers in my libraries along with the main code.

That did not thrill me...

So over time I built a system that would examine the script I had open in Script Debugger, export any relevant handers from my libraries, and assemble a shiny new "flattened" AppleScript ready for posting.

That took less than half a second even on my old hardware thanks to FastScripts and the Satimage.osax.

Because I had this tool available I was much more willing to share complex scripts online, and my rate of posting crippled code went waay down.

If I remember correctly @DanThomas knows how to extract the XML of macros with AppleScript and munge it appropriately to be saved directly to disk as an importable .kmmacro file.

This is on my list of things to learn, because it makes a bunch of stuff possible.

In summation:

  1. I think it's probably possible to build an export system for macros that have dependencies.
    • AppleScript can assemble macros from XML – so theoretically a macro could be examined for dependencies – and a new set of macros could be constructed in a "For Export" macro group.
      • These could then be exported as a single .kmmacros file.
  2. I think this could get very complicated very quickly.
  3. I'm not presently willing to spend time on it.

:sunglasses:

-Chris

3 Likes

Yes it is possible. That's the easy part, honestly.

Very complicated Very quickly. For instance, the issue of how to handle existing "library" macros, and updates to those macros, is much harder than you might think. Much harder.

Me neither, in case anyone wonders.

4 Likes

@peternlewis, @tiffle, @Zabobon, @Nige_S, @ccstone, @DanThomas, thanks for taking the time to weigh in!

There certainly seems to be no clean solution that I've overlooked. Thus I'm going to consider your input, test a few things, and comeback with a plan for the macros that I share.

3 Likes

The thing to consider is what happens when you import a second copy of an existing macro. Each macro has its own UUID, which is always unique even across machines. If you import a macro that already exists (based on the UUID), KM changes the UUID of the one being imported to a new UUID. I'm pretty sure it also changes any macros being imported at the same time, to use the new UUID.

When this happens, there's usually no problem. The old existing macro will be used by whatever was calling it, and the new macros will use the second copy of the existing macro. But it's confusing, and hard to tell which macro is which.

I'm typing this from memory, so be sure to double-check me on this. The easiest and best way to check things like this is to use Parallels to install a virtual macOS machine. Then you can easily test scenarios over and over again, and use Parallels Snapshots to undo your changes. I have several of these virtual machines, with different macOSes on them, because of some HTML stuff I needed to test.

A few years ago I started work on a "Macro Import Manager". The goal was to have it check for existing macros with the same UUID, and based on some well-defined comments in the first action, it could make decisions about replacing them or not. You (the distributor of macro sets) could also configure it to how it should handle existing versions.

I never finished it, because it really didn't seem like anyone was interested, but I got quite a ways into it. If you can deal with Custom HTML Prompts and semi-complex JavaScript/JXA, you're welcome to the code.

There's actually a version of it here somewhere, called "MIM Lite" or something like it. But "all" it does is show what's being installed. It might detect existing macros with the same UUID, but I can't remember.

Good luck. It's a worthy goal, but one not to be achieved easily by any means.

3 Likes

I have a LOT of macros that I have divided up into smaller chunks of shared macros. All well and good, it's good have just one place to update :slight_smile:

Problem is that if I ever want to export a macro, it does not include anything that is running another macro ('Execute a macro').

Is there any way to export and for it to pull together/consolidate all those fragments so that I could share more easily?

I've consolidated your topic with this one, since they are more or less the same.

The answer to your question is no – not presently – and it's unlikely there will ever be an official way to do that. Enterprising folks do abound here on the forum though...

-ccs (Keyboard Maestro Moderator)

2 Likes