- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 83
Add support for permissions and symlinks in os.zip/unzip with vendored zip source code from Apache Ant #374
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
Conversation
| At a first glance, how about we change the package name to  | 
        
          
                build.mill
              
                Outdated
          
        
      | } | ||
| } | ||
|  | ||
| trait ApacheAntZipVendor extends Module { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can probably be a normal object rather than a trait.
It also deserves a comment summarizing the reasons:
- Why we chose to include a third party implementation (because the JDK version doesn't support symlinks)
- Why we chose the Ant implementation over apache-commons (to avoid a dependency on apache-commons-io, and anyway it's where the commons-io implementation came from)
- Why we are shading it (to ensure it doesn't cause classpath conflicts)
- Why we are building it from source (because we only want a subset of the codebase, not the entire thing)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's also compile the shaded apache zip stuff in a os.zip submodule in os/zip/src/ separate from the main OS-Lib codebase in os/src/. It's generally best to avoid mixing generated and hand-written code.
| Needs some small unit tests exercising the permissions/symlink preservation functionality, and a manual test on the  | 
| 
 I would like that too, but Java package private access modifiers are not as flexible as in Scala. You can't have  How about move  | 
| I think not privatizing it is fine. We can just document it as unstable/internal and turn of MIMA enforcement for it | 
| We could also put a shim Scala file in  | 
| 
 I tried it (05ee56b) but it doesn't work. Looks like we can't bypass Java access modifier that way. Got to either keep it public or put  | 
35a2238    to
    c079d8b      
    Compare
  
    via Apache Ant zip tools
to help with IDE and code review
| Just found out you can make symlinks on windows. Wanna take a look at this first before finalizing. | 
| @lihaoyi Need some help on deciding how zipping/unzipping symlinks would work on Windows here. You can create symlink on Windows, but only if (1) run as Administrator (by default) and (2) on NTFS. Currently in this PR on Windows a symlink is 
 This is similar to how Powershell's own Compress-Archive and Expand-Archive work. Also tried Info-ZIP unzip, or more precisely the Cosmo implementation of it. There symlinks are 
 One option is to have the  | 
| I think having  | 
| Went on to implement  For now on Windows I just try unzipping symlinks as symlinks. If that doesn't work, unzip it as a file containing the target path (like what Expand-Archive did), and print out a message. | 
| Sorry for not getting to this @kiendang, will take a look now | 
        
          
                build.mill
              
                Outdated
          
        
      | * To avoid classpath conflicts, the dependency is shaded and compiled from source. Only the `org.apache.tools.zip` | ||
| * package, not the entire Ant codebase, is needed. This only adds < 100kb to Os-Lib jar size. | ||
| */ | ||
| def apacheAntZipSource: T[PathRef] = Task { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make this a def generatedSources folder? That way we won't won't need to commit all the vendored code to the repo, and can rely on the build tool re-generating it on demand as necessary
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
| ): os.Path = { | ||
| stream(os.read.stream(source), dest, excludePatterns, includePatterns) | ||
| checker.value.onWrite(dest) | ||
|  | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you remind me of the reason why we are unable to support permissions and symlinks in unzip.stream? I see that the upstream library has a version of ZipOutputStream in addition to ZipFile. Could we use that to get support for permissions and symlinks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tried it and it doesn't work. It could be due to information on permissions and symlinks are stored as external attributes which are stored inside the zip central directory at the end of the zip file, not together with each zip entry. The Apache Commons Compress doc mentions this (in the ZipArchiveInputStream vs ZipFile section).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ZipFileis able to read the central directory first and provide correct and complete information on any ZIP archive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, that's fine but we just ned to document this limitation somewhere. Maybe on the scaladoc for the unzip.stream class? We can describe the limitation and link to the upstream docs
68795dd    to
    eacd945      
    Compare
  
    | @lihaoyi Done. I made an additional change to preserve permissions for zipped directories, not just files. When zipping, zip entries for directories (not just empty ones) are added. e.g. for  I made shaded code  Adding a  | 
During zipping, add zip entries for all directories (not just empty ones), with permissions set. During unzipping, unzipping enclosing directories before their contents.
for adding to existing zips
| I think this looks good, thanks @kiendang! I will transfer the bounty using your previous bank details | 
Vendored code
Follow the discussion in #356, this adds support for permissions and symlinks in
os.zip/unzipwith vendored zip source code from Apache Ant.The vendored source code is generated by the
os.zip.apacheAntZipSourcetask and put inos/zip. It's shaded with the package renamed fromorg.apache.tools.ziptoos.shaded_org_apache_tools_zip.scala-steward.confwas added and configured to runos.zip.apacheAntZipSourceonorg.apache.ant:antupdates.Features
This brings support for permissions and symlinks to
zip(for creating new zips, not modifying existing ones),zip.streamandunzip. As for modifying existing zips, we would still have to rely onjdk.zipfswhich does not support symlinks.os.zip.openos.zip(create new)os.zip(modify existing)os.zip.streamos.unzipos.unzip.streamTODO
ZipOpsJVM onlyjdk.zipfslike what @sake92 did in Preserve zip files permissions #371