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

Document prependShellScript (was: Assembly JAR produces invalid zip listing) #580

Closed
fitzn opened this issue Mar 29, 2019 · 12 comments
Closed
Labels
bug The issue represents an bug feedback wanted Additional feedback or testing is apreciated workaround-available

Comments

@fitzn
Copy link

fitzn commented Mar 29, 2019

A jar is simply a zip file, but manipulating the mill assembly jar with some Unix-like utilities produces different, incorrect output when compared to that of a "normal" jar produced by the Java jar command. See the following example for details on these differences.

Consider a simple project:

$ find .
.
./build.sc
./foo
./foo/src
./foo/src/example
./foo/src/example/Hello.java
$ cat foo/src/example/Hello.java 
package example;

public class Hello {
  public static void main(String [] args) {
    System.out.println("Args length: " + args.length);
  }
}

This project compiles without issue and produces an assembly jar that executes without issue:

$ mill foo.assembly
$ java -jar out/foo/assembly/dest/out.jar Hello
Args length: 1

Furthermore, the assembly jar file's contents appear to be well-formed:

$ jar tvf out/foo/assembly/dest/out.jar 
     0 Fri Mar 29 10:55:46 EDT 2019 META-INF/
    76 Fri Mar 29 10:55:46 EDT 2019 META-INF/MANIFEST.MF
     0 Fri Mar 29 10:55:46 EDT 2019 example/
   629 Fri Mar 29 10:55:46 EDT 2019 example/Hello.class

However, the following commands show that the generated jar does not behave as expected when we use the jar xvf command. Additionally, it cannot be manipulated by the zip -d command, both of which work for "normal" jars produced by the jar command.

$ cp out/foo/assembly/dest/out.jar original.jar
$ zip -d original.jar META-INF/MANIFEST.MF
	zip warning: Did not find entry for META-INF/

zip error: Zip file structure invalid (was copying META-INF/)
$ jar xvf original.jar   # This should extract the contents of the file
$ ls                     # Observe the contents of the directory are unchanged
build.sc     foo          original.jar out

One command that does work with the mill assembly jar is the regular unzip command. We'll use that command to unzip the jar contents, as demonstrated below:

$ mkdir temp && cd temp && mv ../original.jar . && unzip original.jar 
Archive:  original.jar
warning [original.jar]:  193 extra bytes at beginning or within zipfile
  (attempting to process anyway)
   creating: META-INF/
  inflating: META-INF/MANIFEST.MF    
   creating: example/
  inflating: example/Hello.class     
$ ls
META-INF     example      original.jar

Note the warning error:

warning [original.jar]:  193 extra bytes at beginning or within zipfile

Finally, if we create a "normal" jar using the jar utility and the exact same files that we just unpacked from the mill assembly jar (including the manifest), the resulting jar can be manipulated by the jar xvf (omitted below) and zip -d commands without issue.

$ jar cvmf META-INF/MANIFEST.MF normal.jar example/
added manifest
adding: example/(in = 0) (out= 0)(stored 0%)
adding: example/Hello.class(in = 629) (out= 377)(deflated 40%)
$ jar tvf normal.jar 
     0 Fri Mar 29 11:23:54 EDT 2019 META-INF/
    76 Fri Mar 29 11:23:54 EDT 2019 META-INF/MANIFEST.MF
     0 Fri Mar 29 10:55:46 EDT 2019 example/
   629 Fri Mar 29 10:55:46 EDT 2019 example/Hello.class
$ java -jar normal.jar Check  # Verify the new jar works
Args length: 1
$ zip -d normal.jar META-INF/MANIFEST.MF
deleting: META-INF/MANIFEST.MF
$ zip -d normal.jar META-INF/
deleting: META-INF/
$ jar tvf normal.jar 
     0 Fri Mar 29 10:55:46 EDT 2019 example/
   629 Fri Mar 29 10:55:46 EDT 2019 example/Hello.class

If we compare the original.jar and normal.jar file sizes, the mill assembly jar is 239 bytes larger, which is close to the 193 bytes difference stated in the warning:

$ wc -c original.jar normal.jar 
    1190 original.jar
     951 normal.jar

Giving the warning noted above:

warning [original.jar]:  193 extra bytes at beginning or within zipfile

The assembly jar creation process is the likely culprit for the issue. Given that the normal.jar used the exact same MANIFEST.MF file as the mill assembly jar, I think it's safe to assume that the issue with the mill assembly jar is not related to the contents of the manifest file or any of the Java files in the archive.

Looking at the assembly and regular jar creation logic in mill's Jvm.scala, there are differences in how the two methods produce their files, specifically around the use of JarOutputStream. My guess is the error lies somewhere in these differences.

If I can provide any more information about this issue, please let me know. Thank you for taking a look and, in general, for providing this very useful project.

@fitzn
Copy link
Author

fitzn commented Mar 29, 2019

Some additional information:

  • I am using Mac OS X, so this unzip issue may be related, but that appears to reference PKZIP, a Windows tool.
  • The regular mill jar functionality produces a file that unzips without issue.
  • The file command shows a difference between the mill jar and the mill assembly jar:
$ file out/foo/jar/dest/out.jar out/foo/assembly/dest/out.jar
out/foo/jar/dest/out.jar:      Java archive data (JAR)
out/foo/assembly/dest/out.jar: data

which would seem to indicate that the issue is caused by a difference in the way the jars are produced. As noted above, there is a difference in the way the jars are produced.

@ajrnz
Copy link
Collaborator

ajrnz commented Apr 2, 2019

This happens because mill prepends a shell script to the assembly jar which means it is executable. Ie you can run ./out.jar to start the program.

If you run less out.jar you should be able to see this script.

Most tools which operate on zip files ignore this data (maybe with a warning). If is causing problems you can add:

    def prependShellScript = ""

to your build, which will prevent the script being prepended.

@fitzn
Copy link
Author

fitzn commented Apr 2, 2019

Thanks, @ajrnz. That fixed it.

@fitzn fitzn closed this as completed Apr 2, 2019
@lefou
Copy link
Member

lefou commented Apr 2, 2019

Is this already documented somewhere?

@ajrnz
Copy link
Collaborator

ajrnz commented Apr 3, 2019

Not that I know of

@lefou
Copy link
Member

lefou commented Apr 4, 2019

I'll reopen as a marker, that we should document prependShellScript.

@lefou lefou reopened this Apr 4, 2019
@lefou lefou changed the title Assembly JAR produces invalid zip listing Document prependShellScript (was: Assembly JAR produces invalid zip listing) Apr 4, 2019
@fitzn
Copy link
Author

fitzn commented Apr 4, 2019

Makes sense, @lefou. Thanks.

@lefou lefou added the good-first-issue The fix/solution for the issue is considered easy. A good starting point for newbies. label Apr 5, 2019
@sbly
Copy link
Contributor

sbly commented Nov 24, 2020

Bumping this issue because I just ran into it. Thanks for the investigation @fitzn!

Documenting it is straightforward, but maybe we should consider changing this behavior? I'm not sure the benefits of being able to execute the jar directly is worth the subtle problems this can cause.

@lihaoyi
Copy link
Member

lihaoyi commented Nov 24, 2020

I've hit this issue too, but only once in the last 3 years of using Mill, and worked around it as described above. I use the executable jars regularly, so we should definitely keep them, though it would be nice if we could figure out what's causing the invalid zips and just fixing it

@lefou lefou added bug The issue represents an bug feedback wanted Additional feedback or testing is apreciated workaround-available and removed good-first-issue The fix/solution for the issue is considered easy. A good starting point for newbies. labels Nov 24, 2020
@lefou
Copy link
Member

lefou commented Oct 1, 2021

See also issue #528 and the comments (towards the end).

#528 (comment) and #528 (comment)

Since then we got some fixes applied to os-lib and mill. Could you please comment here, if this issue is still present? And if, can you please post your reproducer so that I can convert it into a test case? Thanks!

@lihaoyi
Copy link
Member

lihaoyi commented Apr 23, 2023

Going to call this fixed, as a dupe of the other ticket. Feel free to open a new issue if you still see problems

@lihaoyi lihaoyi closed this as completed Apr 23, 2023
@lefou
Copy link
Member

lefou commented Apr 23, 2023

@lihaoyi This issue was about documentation in the end. Is this now documented? I yes, please also add the appropriate milestone of the release that fixed it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug The issue represents an bug feedback wanted Additional feedback or testing is apreciated workaround-available
Projects
None yet
Development

No branches or pull requests

5 participants