2013-11-15 5 views
25

अभी तक हमारे पास src नामक एकल स्रोत फ़ोल्डर के साथ एक प्रोजेक्ट संरचना है, जिसमें तीन मॉड्यूल के लिए स्रोत कोड शामिल है। मैं क्या करना चाहता हूं:एकल स्रोत फ़ोल्डर से कई जार ग्रैडल करें

1) संकलित स्रोत कोड। यह आसानी से स्रोतसेट परिभाषा के साथ किया जाता है:

sourceSets { 
    main { 
     java { 
      srcDir 'src' 
     } 
    } 
} 

2) संकलन के परिणाम तीन जार में रखें। अब तीन अलग-अलग कार्यों के माध्यम से

मैं यह कर रहा हूं: मैं तीन 'जार' प्रकार कार्यों के माध्यम से यह कर रहा हूं

  • util.jar

    task utilJar(type: Jar) { 
        from(sourceSets.main.output) { 
         include "my/util/package/**" 
        } 
    } 
    
  • client.jar

    task clientJar(type: Jar) { 
        from(sourceSets.main.output) { 
         include "my/client/package/**" 
        } 
    } 
    
  • server.jar

    task serverJar(type: Jar) { 
        from(sourceSets.main.output) { 
         include "**" 
        } 
        excludes.addAll(utilJar.includes) 
        excludes.addAll(clientJar.includes) 
    } 
    

बात यह है कि server.jar कि client.jar और util.jar के भीतर समाहित नहीं कर रहे हैं सभी वर्गों को शामिल करना चाहिए है। चींटी निर्माण स्क्रिप्ट में हम difference चींटी कार्य का उपयोग कर इस समस्या को हल करते हैं। यह कैसे क्रम में किया जा सकता है (मेरा वर्तमान दृष्टिकोण काम नहीं करता है)?

शायद मेरा दृष्टिकोण पूरी तरह से गलत है। कृपया सलाह दें।

पीएस अभी के लिए हम परियोजना स्रोत कोड फ़ोल्डर संरचना नहीं बदल सकते हैं।

उत्तर

26

मैं यहां अपना कामकाजी समाधान एक उत्तर के रूप में पोस्ट करूंगा (मुझे ग्रेडल के फोरम पर संकेत मिला है)।

ग्रेडल में स्कॉप्स बहुत अजीब चीज हैं :) मैंने सोचा था कि प्रत्येक कार्य परिभाषा कुछ 'कार्य' वर्ग का एक वस्तु बनाती है, जो इस विशेष मामले में 'जारटास्क' जैसी चीज है। फिर मैं अपनी build.gradle स्क्रिप्ट में कहीं से भी कक्षा की किसी भी संपत्ति तक पहुंच सकता हूं। हालांकि, मुझे एकमात्र जगह मिली जहां मैं पैटर्न देख सकता हूं, जो जार फ़ाइल में शामिल हैं - एक कार्य के from ब्लॉक के अंदर। serverJar कार्य की from ब्लॉक में सभी पैटर्न को बाहर करें

1) एक परियोजना स्तरीय संग्रह परिभाषित पैटर्न को रोकने के लिए server.jar

2 से बाहर रखा जाना): तो अब के लिए मेरे कार्य समाधान किया जा सके।

कृपया नीचे

sourceSets { 
    main { 
     java { 
      srcDir 'src' 
     } 
    } 
} 

// holds classes included into client.jar and util.jar, so they are to be excluded from server.jar 
ext.serverExcludes = [] 

// util.jar 
task utilJar(type: Jar) { 
    from(sourceSets.main.output) { 
     include "my/util/package/**" 
     project.ext.serverExcludes.addAll(includes) 
    } 
} 

// client.jar 
task clientJar(type: Jar) { 
    from(sourceSets.main.output) { 
     include "my/client/package/**" 
     project.ext.serverExcludes.addAll(includes) 
    } 
} 

// server.jar 
task serverJar(type: Jar) { 
    from(sourceSets.main.output) { 
     exclude project.ext.serverExcludes 
    } 
} 
+0

यह बहुत अच्छा है, लेकिन आप अन्य परियोजनाओं से अलग '.jar' फ़ाइलों को कैसे संदर्भित करते हैं - उदा। आप 'client.jar' में किसी अन्य उपप्रोजेक्ट में कैसे खींच सकते हैं? – z0r

+0

@ z0r हम बस भंडार में कलाकृतियों को प्रकाशित कर रहे हैं और फिर उन्हें उपप्रोजेक्ट्स में निर्भरता के रूप में उपयोग कर रहे हैं। पीएस प्रतिक्रिया में देरी के लिए खेद है। – vitalidze

16

मुझे लगता है कि दृष्टिकोण गलत है। मैं 3 उप परियोजनाओं के साथ एक परियोजना बनाने की सलाह देते हैं।

project 
- util 
- server (depends on util) 
- client (depends on util) 

किसी कारण से आप वर्ग संरचना उपयोग निर्माण फ़ाइलें इस तरह का परिवर्तन नहीं कर सकते हैं:

settings.gradle

include 'util', 'client', 'server' 

build.gradle

subprojects { 
    apply plugin: 'java' 
} 

project(':util') { 
    sourceSets { 
     main { 
      java { 
       srcDir '../src' 
       include 'util/**' 
      } 
     } 
    } 
} 

project(':server') { 
    sourceSets { 
     main { 
      java { 
       srcDir '../src' 
       include 'server/**' 
      } 
     } 
    } 
    dependencies { 
     compile project(':util') 
    } 
} 

project(':client') { 
    sourceSets { 
     main { 
      java { 
       srcDir '../src' 
       include 'client/**' 
      } 
     } 
    } 
    dependencies { 
     compile project(':util') 
    } 
} 

आपको अभी भी सबप्रोजेक्ट्स के लिए निर्देशिका की आवश्यकता है लेकिन स्रोत एक ही स्थान पर हैं जैसा आप चाहते थे।

जब आप gradle assemble चलाते हैं तो आपके पास कक्षाओं के अलग-अलग सेट के साथ 3 जार होंगे। इस समाधान का लाभ यह है कि हम उचित निर्भरताओं के साथ एक उचित ग्रैडल बहु मॉड्यूल प्रोजेक्ट बनाते हैं, न केवल जार बनाने के लिए कार्य करते हैं।

कृपया Multi-Project Builds पढ़ें।

+0

आपकी टिप्पणी के लिए धन्यवाद। मैंने इस तरह के दृष्टिकोण के बारे में सोचा है, लेकिन निर्देशिका संरचना को बिल्कुल बदलना बहुत वांछनीय है। मुख्य कारण यह है कि हमारे पास बहुत सी एसवीएन शाखाएं हैं (पचास से अधिक) और निर्देशिका संरचना में परिवर्तन के बाद उन्हें मर्ज करने के लिए वास्तविक दर्द होना चाहिए (आपको पता है, पेड़ के संघर्ष)। एक और कारण यह है कि 'उपयोग' और' ग्राहक 'एक दूसरे पर निर्भर करते हैं, इसलिए मुझे लगता है कि वे एक अलग मॉड्यूल में होना चाहिए, जो एक ही समस्या लाता है। मुझे पता है कि यह हमारे स्रोत कोड संरचना डिजाइन में एक गड़बड़ है, लेकिन मेरा मानना ​​है कि ग्रेडल चींटी कर सकते हैं जो चींटी कर सकते हैं :) – vitalidze

+1

@ vitalidze मैंने प्रस्तावित समाधान निर्देशिका संरचना को बदल नहीं रहा है। अतिरिक्त खाली निर्देशिका एक समस्या है? क्या आपके पास निर्भरता चक्र हैं? –

+0

बात यह है कि कक्षाएं फ़ोल्डर द्वारा अलग नहीं होती हैं (यानी ग्राहक, सर्वर, उपयोग)।उदाहरण के लिए, मैं क्लाइंट जार 'ए/बी' और 'जेड/एक्स/वाई' में शामिल हूं, उपयोग में 'क्यू/डब्ल्यू/ई' शामिल है, और सर्वर में सभी बाकी वर्गों को शामिल करना चाहिए, जो 'ए', 'z' के अंतर्गत हो सकते हैं ',' z/x ',' q ',' q/w '। – vitalidze

4

अंतिम संस्करण को देखने के हम अपनी कंपनी में एक ही समस्या है अर्थात्। विरासत कोड जो "अच्छी" परियोजना संरचना में माइग्रेट करना मुश्किल है, और उसी कोडबेस से कई जार बनाने की आवश्यकता है। हमने विभिन्न स्रोतसेट को परिभाषित करने और मानक ग्रैडल का उपयोग करके प्रत्येक स्रोतसेट का निर्माण करने का निर्णय लिया है।

हम तो प्रत्येक sourceSet के लिए jar- और जावाडोक-कार्यों को जोड़ने के लिए iterators का उपयोग करें:

sourceSets.all { SourceSet sourceSet -> 
    Task jarTask = tasks.create("jar" + sourceSet.name, Jar.class) 
    jarTask.from(sourceSet.output) 
    // Configure other jar task properties: group, description, manifest etc 

    Task javadocTask = tasks.create("javadoc" + sourceSet.name, Javadoc.class) 
    javadocTask.setClasspath(sourceSet.output + sourceSet.compileClasspath) 
    javadocTask.setSource(sourceSet.allJava) 
    // Extra config for the javadoc task: group, description etc 

    Task javadocJarTask = tasks.create("javadocJar" + sourceSet.name, Jar.class) 
    javadocJarTask.setClassifier("javadoc") // adds "-javadoc" to the name of the jar 
    javadocJarTask.from(javadocTask.outputs) 
    // Add extra config: group, description, manifest etc 
} 
1

मैं स्वीकार किए जाते हैं जवाब भी साथ प्रिंसिपल में सहमत हैं। मुझे एक प्रोजेक्ट मिला जहां क्लाइंट को एक ही फ़ाइल के अनिवार्य रूप से दो जार की आवश्यकता होती है, सिवाय इसके कि मैनिफेस्ट क्लास-पथ कुंजी द्वारा अलग होता है।

jar { 
    manifest { 
     attributes(
       "Main-Class": platformMainClass, 
       "Implementation-Title": platformDisplayName, 
       "Implementation-Description": platformDescription, 
       "Platform-Version": platformVersion, 
       "Implementation-Version": version, 
       "Build-Assembly-User": System.getProperty("user.name"), 
       "Build-Assembly-Date": new java.util.Date().toString(), 
       "Class-Path": configurations.compile.collect { "lib/"+it.getName() }.join(' ') 
     ) 
    } 

    duplicatesStrategy = DuplicatesStrategy.EXCLUDE 

    exclude([ 'log4j*.properties', 'uk/gov/acme/secret/product/server/**' ]) 
} 

ही प्रकट और फिर स्रोत कोड है:

task applicationClientJar(type: Jar, description: "Creates the Application Client JAR file.") { 
    dependsOn compileJava 
    manifest { 
     attributes(
       "Main-Class": platformMainClass, 
       "Implementation-Title": platformDisplayName, 
       "Implementation-Description": platformDescription, 
       "Platform-Version": platformVersion, 
       "Implementation-Version": version, 
       "Assembly-Date": new java.util.Date().toString() 
     ) 
    } 
    archiveName = "acme-client-${platformVersion}.jar" 
    destinationDir = file("${buildDir}/libs") 
    from sourceSets.main.output 

    duplicatesStrategy = DuplicatesStrategy.EXCLUDE 

    exclude([ 'log4j*.properties', 'uk/gov/acme/secret/product/server/**'  } 

तो Grzegorz अंकन सही है, GAVs साथ दो अलग जार देखते हैं क्योंकि Gradle पता होना चाहिए। मल्टी-मॉड्यूल पसंदीदा विकल्प है।

compile "uk.gov.acme.secret:acme:1.0" // CORE 
compile "uk.gov.acme.secret:acme-client:1.0" 

इस के लिए कॉन्फ़िगर करने के लिए एक ही रास्ता बहु मॉड्यूल Gradle परियोजना का उपयोग करने के लिए और फिर कोर/मुख्य परियोजना के लिए एक संकलन निर्भरता को जोड़ने और/या तैनात है।

project(':common:acme-micro-service-webapp') { 
    dependencies { 
     compile project(':common:acme-core') 
    } 
} 

'एक्मे-सूक्ष्म सेवा-webapp' परियोजना के अंदर, यह सुनिश्चित करता है कि निर्भर 'आम: एकमी कोर' पहली संकलित किया गया है।

पीएस: मैं अभी भी एक बेहतर समाधान का पता लगाने की कोशिश कर रहा हूं।

पीएस पीएस: यदि आप मेवेन का उपयोग कर रहे हैं, तो 'इंस्टॉल' कार्य को हुक करना संभव हो सकता है।

संबंधित मुद्दे