Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial work on Mac patching #12

Open
wants to merge 22 commits into
base: master
Choose a base branch
from

Conversation

colincornaby
Copy link
Contributor

This is kind of ugly but seems to work.

I'm using tgz for the Mac app bundle in since it's a directory. That should be ok in since the Mac client is the only one that will need to look at these manifests - but it would require the client now handle the tar format.

I don't know if there is a better way that doesn't involve tar'ing. I could store as separate files but the logic starts to get more complicated at knowing what to keep and what to delete if we want to get rid of the existing bundle entirely.

@colincornaby
Copy link
Contributor Author

I'm looking through to see if an alternate compression mechanism for directories would be better. Plasma doesn't include a TAR library but it does include a lot of other things. There might be an alternative that works better for Plasma.

urumanifest/commit.py Outdated Show resolved Hide resolved
urumanifest/commit.py Outdated Show resolved Hide resolved
urumanifest/commit.py Outdated Show resolved Hide resolved
urumanifest/commit.py Outdated Show resolved Hide resolved
urumanifest/commit.py Outdated Show resolved Hide resolved
urumanifest/github.py Outdated Show resolved Hide resolved
with archive.open(info, "r") as infile:
with output_path.joinpath(Path(info.filename).name).open("wb") as outfile:
full_path = output_path.joinpath(output_subpath)
Path(os.path.dirname(full_path)).mkdir(parents=True, exist_ok=True)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is going on here? This looks like it's making a new directory in the CWD...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's unpacking the app bundle into the gather directory - but it needs to create any missing folders in the unpack path along the way.

urumanifest/github.py Outdated Show resolved Hide resolved
urumanifest/github.py Outdated Show resolved Hide resolved
urumanifest/commit.py Outdated Show resolved Hide resolved
@colincornaby colincornaby force-pushed the mac-patch branch 3 times, most recently from 1b3049b to ac9fa72 Compare October 16, 2023 03:43
@colincornaby
Copy link
Contributor Author

@Hoikas - I haven't started on matching client side changes yet. I think I'd like feedback on the compression mechanism first.

This PR uses a tarfile in since it's usually complementary for gzip. But that's probably going to require a new library be used in Plasma if our dependencies aren't pulling in a tar library already.

We could also open things up to a wider range of archive formats.

Or I can back off and try to get things working single file. Each file in the bundle gets zipped separately and the flag activates some smarts about treating the parent directory as a single unit. We'd lose some compression by not bundling all the files together but that would be the most compatible with the existing approach.

Copy link
Owner

@Hoikas Hoikas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only concern I have right now is that we're going to be vulnerable to the order that files are hashed inside the tarachive. Hopefully, that won't come back to bite us... I don't think we currently have a tar library in Plasma. I am unfamiliar with the details of the format, so I can't offer any guidance there.

urumanifest/github.py Outdated Show resolved Hide resolved
urumanifest/github.py Outdated Show resolved Hide resolved
urumanifest/github.py Outdated Show resolved Hide resolved
urumanifest/commit.py Outdated Show resolved Hide resolved
urumanifest/commit.py Outdated Show resolved Hide resolved
urumanifest/commit.py Outdated Show resolved Hide resolved
@colincornaby
Copy link
Contributor Author

The only concern I have right now is that we're going to be vulnerable to the order that files are hashed inside the tarachive. Hopefully, that won't come back to bite us... I don't think we currently have a tar library in Plasma. I am unfamiliar with the details of the format, so I can't offer any guidance there.

(Still working through the other feedback.)

Order that files are MD5'd is a risk. We'll have to make sure all ends are sorting the file the same way.

Tar is a Unix archive format usually used with gzip. Strangely - libtar does not work on Windows. But - libarchive does and libarchive can deal with tar archives. But libarchive also supports a wide array of formats so if we wanted to pick something a bit newer we could.

For macOS specifically - libarchive is also included with the system. Although nothing is stopping us from statically linking on macOS - as we would have to do for the other platforms anyway.

urumanifest/commit.py Outdated Show resolved Hide resolved
urumanifest/commit.py Outdated Show resolved Hide resolved
urumanifest/github.py Outdated Show resolved Hide resolved
@@ -46,6 +54,11 @@ def _hash_asset(args: Tuple[Path, Path]) -> Tuple[Path, str, int]:
server_path, source_path = args
# One day, we will not use such a vulnerable hashing algo...
h = hashlib.md5()
if source_path.is_dir():
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something I don't like here: The flag that this is an app bundle seems to be encoded later and isn't available yet. So I'm checking to see if the asset is a directory which is kind of gross. Ideally I'd only be checking the bitmask for the bundle property.

@colincornaby
Copy link
Contributor Author

Going to promote this to ready to review.

The only odd output that I think is present here is that we archive to top level of the bundle instead of the bundle itself. I.E. if you have plClient.app/Contents, the top level of the archive will have Contents and not plClient.app. Even though it's odd - I still think it's proper. The manifest contains the plClient.app destination name - and not encoding that level into the archive avoids duplication between the manifest and the archive, and avoids possible naming conflicts and corner cases. I.E. if the manifest said the name was UruExplorer.app but the manifest said plClient.app - thats a corner case I don't want to deal with.

@colincornaby colincornaby marked this pull request as ready for review June 30, 2024 19:39
@colincornaby
Copy link
Contributor Author

The bundle flag is not properly being carried through the script - I'll dig in and figure out why it isn't landing in the final manifest.

urumanifest/commit.py Outdated Show resolved Hide resolved
urumanifest/commit.py Outdated Show resolved Hide resolved
@@ -191,6 +191,7 @@ def track_client_dependency(client_path: Path, server_path: Path):

def track_manifest_dependency(client_path: Path, server_path: Path, category: str, manifest_names):
flags = ManifestFlags.installer if category in gather_installers else 0
flags |= ManifestFlags.bundle if client_path.suffix == ".app" else 0
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to have the bundle extension in constants.py instead of as a magic string at the very minimum. On the other hand, the rest of the script (i.e. the Windows support) doesn't try to use magic strings in the filename to identify what flags need to be applied. Instead, we use the the keys from the control json files to assign a category. Then, we apply flags from the category here. So, what we should really be doing is have a dict in the control json to represent the new mac bundle. github.py will need to be updated to generate that part of the fake control json.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can take a look at that.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is still outstanding?

Comment on lines 394 to 402
client_folder_name = "client"
if len(member_path.parts) >= 2 and member_path.parts[0] == client_folder_name:
is_mac_app_bundle = member_path.parts[1].endswith(".app")
if not i.is_dir() and len(member_path.parts) == 2:
yield ArtifactInfo(path=member_path.name, zipinfo=i, name=member_path.name)
elif is_mac_app_bundle and not i.is_dir():
# remove "client/"
path = member_path.relative_to(client_folder_name)
yield ArtifactInfo(path=path, zipinfo=i, name=member_path.parts[1])
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is going on here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is constructing paths to the bundle, but not the files in the bundle. For example:
client/plClient.app/Contents/Info.plist
Should only be added to the control json as:
plClient.app

Comment on lines +66 to +68
"macInternal": _manifests("MacThinInternal", None, "MacInternal"),
"macExternal": _manifests("MacThinExternal", None, "MacExternal"),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these legacy manifests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

macInternal and macExternal are current. Should they be declared as something else?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They should probably be listed before the comment that says legacy manifests follow.

Comment on lines +86 to +90
"macexternal": _directorytuple("", "client/mac/external"),
"macinternal": _directorytuple("", "client/mac/internal"),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The filename case doesn't match above. Also, just to make sure - we are assuming that mac clients are universal binaries?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thats the assumption. It wouldn't really make sense to have it be a universal binary locally and then a processor specific binary.

That said - that will make things messy when Apple eventually gets around to cutting Intel support from their tools. But that eventuality could be dealt with like any other platform we discontinue support for.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that currently CI is not generating universal binaries (because of vcpkg limitations). In theory we could figure out a way to lipo them together into a universal binary when we attach them to the published release.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: the gather_lut keys are expected to be all lowercase.

Comment on lines +86 to +90
"macexternal": _directorytuple("", "client/mac/external"),
"macinternal": _directorytuple("", "client/mac/internal"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that currently CI is not generating universal binaries (because of vcpkg limitations). In theory we could figure out a way to lipo them together into a universal binary when we attach them to the published release.

Comment on lines +161 to +167
"plasma-macos-x64-internal-release": "macInternal",
"plasma-macos-x64-external-release": "macExternal",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noting that these are Intel x86_64 binaries (which is probably the best option for the moment, but they are not universal because they do not include arm64)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah - that still needs to be done on the CI side. For now, I'm kind of assuming whatever the platforms should be is what is provided by CI.

@colincornaby
Copy link
Contributor Author

I have a structure that I'm working on to separate the Mac bundle - but I don't know if it really fits with how things are supposed to work.

{
  "macExternal": [
    "banner.png",
    "[email protected]",
    "resource.dat"
  ],
  "macBundle": [
    "UruExplorer.app"
  ]
}

This would de-associated the macBundle with macExternal. But I don't think a child map inside macExternal is supported?

@Hoikas
Copy link
Owner

Hoikas commented Jul 2, 2024

But I don't think a child map inside macExternal is supported?

No, I don't think any of the code is equipped to handle dictionaries inside of dictionaries.

You may want to separate macBundle into macBundleExternal and macBundleInternal to allow shipping down both internal and external release apps.

@colincornaby
Copy link
Contributor Author

@Hoikas - That was going to be my next question. My assumption is somewhere deeper in the code I need to take those keys and pair them with a destination.

@colincornaby
Copy link
Contributor Author

I have an initial version in that uses a custom Gather key for the Mac bundle. However - deeper sections of code are still doing a folder check.

Copy link
Owner

@Hoikas Hoikas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still need to do a complete rereview, but this is what I see for the two new commits.

urumanifest/github.py Outdated Show resolved Hide resolved
urumanifest/commit.py Outdated Show resolved Hide resolved
urumanifest/commit.py Outdated Show resolved Hide resolved
Comment on lines +86 to +90
"macexternal": _directorytuple("", "client/mac/external"),
"macinternal": _directorytuple("", "client/mac/internal"),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: the gather_lut keys are expected to be all lowercase.

@@ -191,6 +191,7 @@ def track_client_dependency(client_path: Path, server_path: Path):

def track_manifest_dependency(client_path: Path, server_path: Path, category: str, manifest_names):
flags = ManifestFlags.installer if category in gather_installers else 0
flags |= ManifestFlags.bundle if client_path.suffix == ".app" else 0
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is still outstanding?

urumanifest/github.py Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants