I want to sign two dozen jar files using jarsigner, giving the password only once.
Giving multiple files to jarsigner is not possible, according to the man page and using a for-loop on the command line still forces me to input the password for every file.
I would prefer a solution for the command line, but would be okay with ant/maven solution.
System is Linux.
How do I sign a dozen jar-files, giving the password only once?
Here is a snippet from the Ant build file for PSCode - it signs a slew of Jars. The trick is in the foreach element.
<target name="createjars"
depends="compile"
description="Jars the compiled classes">
<mkdir dir="${build}/jar/" />
<foreach target="jar.package" param="package" inheritall="true">
<path>
<dirset dir="${src}/java/org/pscode" includes="**/*" />
</path>
</foreach>
</target>
..and..
<target name='jar.package'>
<script language='javascript'>
<![CDATA[
prop = pscode.getProperty('package');
index1 = prop.lastIndexOf('pscode') + 7;
index2 = prop.length();
prop1 = prop;
path = prop1.substring( index1, index2 );
path2 = path.replaceAll('\\\\','/');
pscode.setProperty('path', path2 );
name = path2.replaceAll('/','.');
pscode.setProperty('jar.name', name + '.jar' );
]]>
</script>
<xmlproperty file="${src}/java/org/pscode/${path}/manifest.xml" />
<!-- echo message='jar.name: ${jar.name} *** ${application.title}' / -->
<if>
<not>
<uptodate targetfile='${build}/dist/lib/${jar.name}' >
<srcfiles dir= '${build}/share/org/pscode/${path}' includes='*.class'/>
</uptodate>
</not>
<then>
<jar
destfile='${build}/dist/lib/${jar.name}'
index='true'
update='true'>
<manifest>
<attribute name="Implementation-Title" value="${application.title}" />
<attribute name="Implementation-Vendor" value="${vendor}" />
<attribute name="Implementation-Vendor-Id" value="org.pscode" />
<attribute name='Implementation-Version' value='${now}' />
</manifest>
<fileset dir='${build}/share'>
<include name='org/pscode/${path}/*.class' />
</fileset>
<fileset dir='${src}/java'>
<include name='org/pscode/${path}/*.png' />
<include name='org/pscode/${path}/*.jpg' />
<include name='org/pscode/${path}/*.gif' />
<include name='org/pscode/${path}/*.xml' />
<include name='org/pscode/${path}/*.html' />
<include name='org/pscode/${path}/*.ser' />
</fileset>
</jar>
</then>
</if>
<!-- If the Jar is updated, any previous signatures will be invalid, it
needs to be signed again. We cannot use the issigned condition since
that merely checks if a Jar is signed, not if the digital signatures are
valid. -->
<exec
executable='${jar.signer}'
resultproperty='jar.signer.result.property'
outputproperty='jar.signer.output.property'>
<arg value='-verify' />
<arg value='${build}/dist/lib/${jar.name}' />
</exec>
<if>
<or>
<not>
<equals arg1='${jar.signer.result.property}' arg2='0' />
</not>
<or>
<contains
string='${jar.signer.output.property}'
substring='unsigned'
casesensitive='false' />
<or>
<contains
string='${jar.signer.output.property}'
substring='SecurityException'
casesensitive='false' />
</or>
</or>
</or>
<then>
<signjar
jar='${build}/dist/lib/${jar.name}'
alias='pscode'
storepass='${sign.password}'
force='true'
verbose='${verbose}'
keystore='${user.home}/${sign.pathfilename}' />
</then>
</if>
</target>
Just for the records: jarsigner is able to read the keystore and key passwords from a file or from an environment variable, using the -keypass / -storepass command line option together with the :file or the :env modifier.
So, it's possible to put each of the passwords in a file (in my example: ~/.storepass and ~/.keypass) and use a for loop like this to sign all jars in the current directory using the key key_alias:
for i in ./*.jar; do jarsigner -storepass:file ~/.storepass -keypass:file ~/.keypass "$i" key_alias;done
To make jarsigner read the passwords from an env variable, you'll have to create those variables first:
export storepass="mystorepassword"
export keypass="mykeypassword"
Now, the loop would look like:
for i in ./*.jar; do jarsigner -storepass:env storepass -keypass:env keypass jarfile.jar key_alias;done
Related
I want to update the content of a file from my local folder to svn, note that the file exists on svn.
first I am checking out with depth empty.
then I run update on the script
<svn refid="svn.settings" logFile="${directory}/checkout_log.log">
<checkout url="${svn_path}"
destpath="${full_path}"
revision="HEAD" depth="empty"
/>
<update recurse="false" revision="HEAD" dir="D:\Update\SVNCheckout\T\" file= "test.sql" />
</svn>
however In the log file its sayes
Skipped 'test.sql'
Summary of conflicts:
Skipped paths: 1
<Update> finished.
ok I understand there is conflict , however how I can svn resolve the script
To avoid conflicts it is better to first check out, then modify the checked out file and then try to check it in. If this fails, then remove all temporary files and try it again.
The overall procedure looks like this (using Ant Contrib as an extension to plain Ant):
<var name="finished" value="false" />
<for list="1,2,3,4,5,5,6,7,8,9,10" param="trynr">
<sequential>
<if>
<equals arg1="${finished}" arg2="false" />
<then>
<echo message="#########################################" />
<echo message="# trynr=#{trynr}" />
<echo message="#########################################" />
<trycatch property="errormsg" reference="exceptionObject">
<try>
<!-- Delete old checked out files -->
<delete .../>
<!-- Check out the file -->
<!-- Modify the file -->
<!-- Commit the file -->
<var name="finished" value="true" />
</try>
<catch>
<echo message="Update failed." />
<echo message="Error message: ${errormsg}" />
<if>
<equals arg1="#{trynr}" arg2="10" />
<then>
<echo message="Giving up after #{trynr} attempts." />
<fail message="Unable to update file. Giving up after #{trynr} attempts." />
</then>
<else>
<echo message="Trying again in 2 seconds ..." />
<sleep seconds="2"/>
</else>
</if>
</catch>
</trycatch>
</then>
<else />
</if>
</sequential>
</for>
I built a jar file using the following build.xml below:
<project name="sampleproject">
<!--Source Directory-->
<property name="src.dir" value="src" />
<property name="deploy.name" value="samplejar.jar" />
<property name="lib.dir" value="./lib" />
<property name="deploy.dir" value="target" />
<property name="compile.dir" value="target/classes" />
<!--Define directory name for third party libraries-->
<property name="jar-all" location="${lib.dir}" />
<!--Fileset is a group of files, here **/* matches all jar files across all directory levels-->
<fileset id="jars" dir="${jar-all}">
</fileset>
<!--Setting the classpath-->
<path id="classpath">
<fileset refid="jars" />
<pathelement location="." />
<pathelement location="${src.dir}" />
<pathelement location="${compile.dir}" />
</path>
<path id="cp">
<fileset refid="jars" />
</path>
<pathconvert property="classpath.path" refid="cp" pathsep=" " dirsep="/">
<map from="${jar-all}" to="lib" />
</pathconvert>
<echo>${classpath}</echo>
<!--Clean-->
<target name="clean">
<delete dir="${deploy.dir}" />
</target>
<!--Jar-->
<target name="jar" depends="compile">
<jar destfile="${deploy.dir}/${deploy.name}.jar" basedir="${compile.dir}">
<manifest>
<attribute name="Main-Class" value="main.java.Main" />
<attribute name="Class-Path" value="${classpath.path}" />
</manifest>
<include name="${src.dir}/META-INF/persistence.xml" />
<restrict>
<not>
<or>
<name name="**/*.RSA" />
<name name="**/*.SF" />
<name name="**/*.DSA" />
</or>
</not>
<archives>
<zips>
<fileset dir="lib" includes="**/*.jar" />
</zips>
</archives>
</restrict>
</jar>
</target>
<!--Compile-->
<target name="compile">
<mkdir dir="${compile.dir}" />
<javac includeantruntime="false" srcdir="${src.dir}" destdir="${compile.dir}">
<classpath refid="classpath" />
</javac>
</target>
</project>
My folder structure is like this:
.
./.settings
./bin
./bin/main
./bin/main/java
./bin/META-INF
./lib
./lib/aws
./lib/hibernate
./src
./src/main
./src/main/java
./src/META-INF
./target
./target/classes
./target/classes/main
./target/classes/main/java
My MANIFEST.MF
Created-By: 1.8.0_45-b14 (Oracle Corporation)
Built-Date: ${TODAY}
Main-Class: main.java.Main
Class-Path: lib/activation.jar lib/aws/aws-java-sdk-1.3.2.jar lib/aws/
httpclient-4.1.1.jar lib/aws/httpcore-4.4.1.jar lib/aws/mail-1.4.3.ja
r lib/aws/stax-1.2.0.jar lib/aws/stax-api-1.0.1.jar lib/commons-beanu
tils-1.8.3.jar lib/commons-codec-1.4.jar lib/commons-configuration-1.
8.jar lib/commons-httpclient-3.0.1.jar lib/commons-io-2.1.jar lib/com
mons-lang-2.4.jar lib/commons-logging-1.1.1.jar lib/hibernate/antlr-2
.7.7.jar lib/hibernate/c3p0-0.9.1.jar lib/hibernate/commons-collectio
ns-3.2.1.jar lib/hibernate/dom4j-1.6.1.jar lib/hibernate/hibernate-c3
p0-4.0.1.Final.jar lib/hibernate/hibernate-commons-annotations-4.0.1.
Final.jar lib/hibernate/hibernate-core-4.0.1.Final.jar lib/hibernate/
hibernate-entitymanager-4.0.1.Final.jar lib/hibernate/hibernate-jpa-2
.0-api-1.0.1.Final.jar lib/hibernate/javassist-3.15.0-GA.jar lib/hibe
rnate/jboss-logging-3.1.0.CR2.jar lib/hibernate/jboss-transaction-api
_1.1_spec-1.0.0.Final.jar lib/jackson-all-1.9.5.jar lib/log4j-1.2.16.
jar lib/mail.jar lib/mongo-2.8.0.jar lib/morphia-0.99.jar lib/mysql-c
onnector-java-5.1.12-bin.jar lib/mysql-connector-java-5.1.25-bin.jar
lib/org.json.jar lib/ymmi-utilities-2.0.jar
Whenever I run the jar produced it gives me, Error: Could not find or load main class main.java.Main.
Also, I want to include lib folder & it's subfolders as well since it contains the libraries required to run the jar.
Before it gave me, No Persistence provider for EntityManager named but I solved that by using <include name="${src.dir}/META-INF/persistence.xml" />. Any where I am might wrong?
Your problem is the <include> element in the jar task.
I executed your script and the Main.class file is not added to the jar.
Replace the
<include
by
<fileset dir="${src.dir}" includes="META-INF/persistence.xml" />
This way it will still add all files located in your ${compile.dir}.
Are you new to java ? Normally you put your source files in src/main/java and resources in src/main/resources.
These folders are the root folder of your classpath meaning: If your project classes would be in package org.myproject, than you would put the Main.java file in src/main/java/org/myproject/Main.java
In your build script you than set the property "src.dir" to "src/main/java".
With all resources (=files which do not need to be compiled but must be available in the jar) in src/main/resources the fileset element in the jar task could just be:
<fileset dir="scr/main/resources"/>
This way all resource files you plan to add to your project will automatically added to your jar.
Why do I tell you this ? If one day you would think of using maven instead of ant, maven expects the sources to be in src/main/java and resources in src/main/resources. (https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html)
Regarding you other dependant jars:
Now you include all jars twice: you add the content of them using the <archives> element within the jar and you define them in the Class-Path attribute of the manifest.mf file.
If you really like to build a single jar containing all dependant files, you don't need to specify the manifest attribute Class-Path.
If you want your jar file containing only your files and deliver the dependant jars separately: remove the <archives> element within the jar task.
I updated to Netbeans 8.0.1 from 7.0.1 and my java program compiles fine if 'Web Start' is disabled. As soon as 'Web Start' is enabled I get the following error:
C:\NetBeansProjects\SearchCriteriaEditor\nbproject\jnlp-impl.xml:480:
unsupported element customize
in this section of the jnlp-impl.xml file:
<target name="-do-jar-jnlp-application" depends="-init-filename,-test-jnlp-type,-init-macrodef-copylibs" if="is.application+mkdist.available">
<j2seproject3:copylibs manifest="${tmp.manifest.file}">
<customize>
<attribute name="Main-Class" value="${main.class}"/>
</customize>
</j2seproject3:copylibs>
<echo>To run this application from the command line without Ant, try:</echo>
<property location="${jnlp.dest.dir}/${jnlp.file}" name="jnlp.file.resolved"/>
<echo>javaws "${jnlp.file.resolved}"</echo>
</target>
The fix, as I understand it is to: 'add following to customized junit macro definition:'
<attribute default="" name="testmethods"/>
<element name="customize" optional="true"/>
<customize/>
Trouble is I have no idea where that is, nor have I modified my ant file in any way...can anyone give me a bit more information? I assume the fix goes somewhere in the jnlp-impl.xml file; I just have no idea where to put it.
Edit update: added all sections with references to 'copylibs' in the jnlp-impl.xml file-
<target name="-test-jnlp-type" depends="-test-jnlp-enabled" if="is.jnlp.enabled">
<condition property="is.applet">
<equals arg1="${jnlp.descriptor}" arg2="applet" trim="true"/>
</condition>
<condition property="is.application">
<equals arg1="${jnlp.descriptor}" arg2="application" trim="true"/>
</condition>
<condition property="is.component">
<equals arg1="${jnlp.descriptor}" arg2="component" trim="true"/>
</condition>
<condition property="is.applet+mkdist.available">
<and>
<isset property="libs.CopyLibs.classpath"/>
<istrue value="${is.applet}"/>
</and>
</condition>
<condition property="is.application+mkdist.available">
<and>
<isset property="libs.CopyLibs.classpath"/>
<istrue value="${is.application}"/>
</and>
</condition>
<condition property="is.component+mkdist.available">
<and>
<isset property="libs.CopyLibs.classpath"/>
<istrue value="${is.component}"/>
</and>
</condition>
</target>
......
<target name="-do-jar-jnlp-application" depends="-init-filename,-test-jnlp-type,-init-macrodef-copylibs" if="is.application+mkdist.available">
<j2seproject3:copylibs manifest="${tmp.manifest.file}">
<customize>
<attribute name="Main-Class" value="${main.class}"/>
</customize>
</j2seproject3:copylibs>
<echo>To run this application from the command line without Ant, try:</echo>
<property location="${jnlp.dest.dir}/${jnlp.file}" name="jnlp.file.resolved"/>
<echo>javaws "${jnlp.file.resolved}"</echo>
</target>
<target name="-do-jar-jnlp-component" depends="-test-jnlp-type,-init-macrodef-copylibs" if="is.component+mkdist.available">
<j2seproject3:copylibs manifest="${tmp.manifest.file}"/>
</target>
Thanks in advance.
<j2seproject3:copylibs invokes the macrodef copylibs with the namespace prefix j2seproject3. There should be a place in the buildfile where the copylibs macro is defined, in a way similar (but not necessarily exact) to:
<macrodef name="copylibs" uri="http://www.netbeans.org/ns/j2se-project/3">
The above line should logically exist inside the -init-macrodef-copylibs target, and this is where the customize element should be defined as well. Below is the snippet based on a sample NetBeans project I have. The content will probably not match exactly the one you have, so take my answer with a grain of salt:
<macrodef name="copylibs" uri="http://www.netbeans.org/ns/j2se-project/3">
... <!-- some attributes may be defined here first -->
<element name="customize" optional="true"/> <!-- customize should be defined here -->
<sequential>
...
<!-- somewhere in the macrodef -->
<copylibs compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
<fileset dir="${build.classes.dir}"/>
<manifest>
<attribute name="Class-Path" value="${jar.classpath}"/>
<customize/> <!-- this is where customize is used -->
</manifest>
</copylibs>
...
</sequential>
</macrodef>
Is there a way to include or exclude certain files based on a condition in Apache Ant (1.8.3)? For instance, I have a macrodef that takes an attribute. I would like to include certain files if the attribute's value matches xyz:
<macrodef name="pkgmacro">
<attribute name="myattr" />
<sequential>
<zip destfile="${dist}/#{myattr}.war">
<fileset dir="${dist}/webapp" >
<include name="**/#{myattr}/**" />
<exclude name="WEB-INF/config/**" />
<!-- if #{myattr} = "xyz", then
<include name="PATH/TO/file.xml" />
-->
</fileset>
<zipfileset dir="${ear}/#{myattr}/WEB-INF/" includes="*.xml" prefix="WEB-INF/" />
</zip>
</sequential>
</macrodef>
For instance, if myattr value is xyz, I would like to include the commented file in portion above.
Fileset can use nested include/exlucde patternsets with if/unless
Attribute. The pattern is included/excluded when a named property is set or not, so no ant addons needed.Some snippet :
<project>
<!-- property that triggers your include/exclude
maybe set via condition in some other target .. -->
<property name="foo" value="bar"/>
<macrodef name="pkgmacro">
<attribute name="myattr" />
<sequential>
<fileset dir="C:/whatever" id="foobar">
<!-- alternatively
<include name="*.bat" unless="#{myattr}"/>
-->
<include name="*.bat" if="#{myattr}"/>
</fileset>
<!-- print fileset contents -->
<echo>${toString:foobar}</echo>
</sequential>
</macrodef>
<pkgmacro myattr="foo"/>
</project>
--EDIT after comment --
The if/unless attribute after include name/exclude name checks whether the given value is a property which is set (when using if="..") or not set (when using unless="..") in the ant project scope - it doesn't check for a specific value.
<include name="*.xml" unless="foo"/>
means include is only active if no property named foo is set in your project
<include name="*.xml" if="foo"/>
means include is only active if property named foo is set in your project
Works fine for me , used Ant 1.7.1, had no Ant 1.8.x around right now :
<project>
<echo>$${ant.version} => ${ant.version}</echo>
<macrodef name="pkgmacro">
<attribute name="myattr"/>
<sequential>
<condition property="pass">
<equals arg1="#{myattr}" arg2="xyz" />
</condition>
<fileset dir="C:/whatever" id="foobar">
<include name="*.bat" if="pass" />
</fileset>
<echo>${toString:foobar}</echo>
</sequential>
</macrodef>
<pkgmacro myattr="xyz"/>
</project>
output :
[echo] ${ant.version} => Apache Ant version 1.7.1 compiled on June 27 2008
[echo] switchant.bat;foobar.bat;foo.bat
-- EDIT after comment --
Using serveral include patterns works fine :
...
<fileset dir="C:/whatever" id="foobar">
<include name="*.xml" if="pass" />
<include name="*.bat" if="pass"/>
<include name="**/*.txt" if="pass"/>
</fileset>
...
maybe you're using the wrong patterns ?
-- EDIT after comment --
Here is the reference to <local> task which is needed to work with the properties in the current scope, in this case, <sequential>:
<macrodef name="pkgmacro">
<attribute name="myattr"/>
<sequential>
<!-- make property pass mutable -->
<local name="pass"/>
<condition property="pass">
<equals arg1="#{myattr}" arg2="xyz" />
</condition>
<fileset dir="C:/whatever" id="foobar">
<include name="*.xml" if="pass" />
<include name="*.bat" if="pass" />
<include name="**/*.txt" if="pass" />
</fileset>
<!-- print value of property pass and fileset contents -->
<echo>$${pass} = ${pass}${line.separator}${toString:foobar}</echo>
</sequential>
</macrodef>
if you can use ant-contrib, then try this:
<contrib:if>
<equals arg1="${myattr}" arg2="xyz" />
<then>
<include name="PATH/TO/file.xml" />
</then>
</contrib:if>
if you can't use ant-contrib, try this:
http://jaysonlorenzen.wordpress.com/2010/03/10/apache-ant-if-else-condition-without-ant-contrib/
I've got the following markup:
<?xml version="1.0" ?>
<project name="SampleBuild" default="compile" basedir=".">
<property name="SvnAntDir" value="C:/Program Files/Apache/svnant-1.2.1/doc" />
<property name="src" value="_src_" />
<property name="build" value="_build_"/>
<property name="dist" value="${build}/_jars_" />
<path id= "svnant.classpath" >
<fileset dir= "${SvnAntDir}" >
<include name= "*.jar" />
</fileset>
</path>
<target name="pre-cleanup">
<delete dir="${src}" />
<delete file="${dist}/Project.jar" />
<delete includeEmptyDirs="true" failonerror="false">
<fileset dir="${build}/_classes_/sevgok/" />
</delete>
<mkdir dir="${src}" />
<tstamp />
</target>
<target name="checkout" depends="pre-cleanup">
<typedef resource="org/tigris/subversion/svnant/svnantlib.xml" classpathref="svnant.classpath" />
<svn>
<checkout url="svn://p-subversion/Project/trunk" revision="HEAD" destPath="${src}" />
</svn>
</target>
<target name="compile" depends="checkout">
<javac srcdir="${src}" destdir="${build}/_classes_" debug="on" debuglevel="lines,vars,source">
<classpath>
<pathelement path="${classpath}" />
<fileset dir="./_libs_">
<include name="*.jar" />
<include name="*.zip" />
</fileset>
</classpath>
</javac>
</target>
</project>
Problem occurs when trying to make a build. The error message is next:
checkout: [svn] <Checkout> started ...
[svn] svn: svn://p-subversion/Project/trunk` doesn't exist
[svn] svn: svn://p-subversion/Project/trunk` doesn't exist
[svn] <Checkout> failed!
Build FAILED
C:\build.minimal.xml: (line of code which points to <svn> openning tag): Can't checkout.`
Simultaneously it is possible to make a checkout with Tortoise SVN client using the url.
Help!
EDIT
I tried using -v key when building and got the following:
Caused by: org.tigris.subversion.svnclientadapter.SVNClientException: org.tigris
.subversion.javahl.ClientException: svn: URL 'svn://p-subversion/Project/trunk
' doesn't exist
EDIT
Is there any alternative to SvnAnt? It would be great if it was also well documentated.
Thanks
EDIT
So code that works for me is:
<target name="checkout" depends="pre-cleanup">
<exec dir="${basedir}" executable="svn" failonerror="true">
<arg line="checkout -r ${revision} ${SvnUrl} ${src}" />
</exec>
</target>
where ${SvnUrl} is the same URL I used before.
If svnant does not work at all you could just execute svn from the command line:
<exec executable="svn" dir="DIRECTORY_WHERE_COMMAND_EXECUTES">
<arg line="checkout svn://p-subversion/Project/trunk $src"/>
</exec>
You would have to install a svn command line client. Make sure, that you add the bin-Directory of the client to the PATH.
But take care to install the same client version as your tortoise client. If they mismatch they will make the working copy unaccessible for the other.
What is p-subversion supposed to be? SVN URLs, just like HTTP URLs, begin with a hostname. If p-subversion isn't a hostname that will point to your computer, then the checkout will fail. Perhaps it should look more like this?
svn://localhost/p-subversion/Project/trunk
[edit]If it's a Windows share...
file://p-subversion/Project/trunk
the svn:// URL assumes a hostname, but in the case of a share some other part of the OS is already negotiating the TCP connection. Refer to it like you would any other folder.