From 843820ea9f357220d69f3795f3289ee41eed355c Mon Sep 17 00:00:00 2001 From: Kostya Date: Sun, 23 Aug 2026 14:05:29 +0000 Subject: model: relocate market DTOs out of the flat api package Move AccountDTO/MarketDTO/MarketStateDTO/PurchaseReceiptDTO/TradeRowDTO out of the catch-all api package into model.market (and LedgerDTO into model.ledger), matching the existing model.event convention so DTOs live next to the domain they describe rather than in the interface package. Relocate LedgerMapper from mapper.v2 to infrastructure.adapter to match the module's established package layout, and update all call sites and imports accordingly. Also register the ui-desktop module in the build tooling: add it to MODULES, add openjfx to the shipped runtime libs, and generalize package.sh so each executable module (ui-console, ui-desktop) gets its own Main-Class/Class-Path manifest and run script instead of special-casing ui-console. Fold long Class-Path manifest lines at 72 bytes per the JAR spec, since adding ui-desktop's dependencies pushed the line past the limit. --- api/src/main/java/market/guess/api/AccountDTO.java | 7 -- .../java/market/guess/api/GuessMarketContext.java | 1 + api/src/main/java/market/guess/api/MarketDTO.java | 3 - .../main/java/market/guess/api/MarketStateDTO.java | 11 -- .../java/market/guess/api/PurchaseReceiptDTO.java | 10 -- .../main/java/market/guess/api/TradeRowDTO.java | 4 - .../market/guess/model/event/EventDetailDTO.java | 4 +- .../java/market/guess/model/ledger/LedgerDTO.java | 6 ++ .../java/market/guess/model/market/MarketDTO.java | 3 + .../market/guess/model/market/MarketStateDTO.java | 11 ++ .../guess/model/market/PurchaseReceiptDTO.java | 10 ++ .../market/guess/model/market/TradeRowDTO.java | 4 + .../guess/service/LocalGuessMarketContext.java | 4 +- .../infrastructure/adapter/LedgerMapper.java | 10 ++ .../infrastructure/mapper/v2/LedgerMapper.java | 11 -- .../java/market/guess/service/domain/Event.java | 6 +- .../java/market/guess/service/domain/Market.java | 2 +- .../infrastructure/adapter/LedgerMapperTest.java | 113 +++++++++++++++++++++ .../infrastructure/mapper/v2/LedgerMapperTest.java | 103 ------------------- tools/_util.sh | 27 ++++- tools/package.sh | 75 ++++++++------ .../market/guess/ui/console/io/InputProcessor.java | 7 +- 22 files changed, 236 insertions(+), 196 deletions(-) delete mode 100644 api/src/main/java/market/guess/api/AccountDTO.java delete mode 100644 api/src/main/java/market/guess/api/MarketDTO.java delete mode 100644 api/src/main/java/market/guess/api/MarketStateDTO.java delete mode 100644 api/src/main/java/market/guess/api/PurchaseReceiptDTO.java delete mode 100644 api/src/main/java/market/guess/api/TradeRowDTO.java create mode 100644 api/src/main/java/market/guess/model/ledger/LedgerDTO.java create mode 100644 api/src/main/java/market/guess/model/market/MarketDTO.java create mode 100644 api/src/main/java/market/guess/model/market/MarketStateDTO.java create mode 100644 api/src/main/java/market/guess/model/market/PurchaseReceiptDTO.java create mode 100644 api/src/main/java/market/guess/model/market/TradeRowDTO.java create mode 100644 service/src/main/java/market/guess/service/catalog/infrastructure/adapter/LedgerMapper.java delete mode 100644 service/src/main/java/market/guess/service/catalog/infrastructure/mapper/v2/LedgerMapper.java create mode 100644 service/src/test/java/market/guess/service/catalog/infrastructure/adapter/LedgerMapperTest.java delete mode 100644 service/src/test/java/market/guess/service/catalog/infrastructure/mapper/v2/LedgerMapperTest.java diff --git a/api/src/main/java/market/guess/api/AccountDTO.java b/api/src/main/java/market/guess/api/AccountDTO.java deleted file mode 100644 index 134c88b..0000000 --- a/api/src/main/java/market/guess/api/AccountDTO.java +++ /dev/null @@ -1,7 +0,0 @@ -package market.guess.api; - -import java.util.List; -import market.guess.model.ledger.LedgerEntryDTO; - -public record AccountDTO( - String owner, String balance, boolean blocked, List entries) {} diff --git a/api/src/main/java/market/guess/api/GuessMarketContext.java b/api/src/main/java/market/guess/api/GuessMarketContext.java index e11defb..4edb437 100644 --- a/api/src/main/java/market/guess/api/GuessMarketContext.java +++ b/api/src/main/java/market/guess/api/GuessMarketContext.java @@ -2,6 +2,7 @@ package market.guess.api; import java.math.BigDecimal; import market.guess.model.event.EventDetailDTO; +import market.guess.model.market.PurchaseReceiptDTO; public interface GuessMarketContext { Result placeOrder( diff --git a/api/src/main/java/market/guess/api/MarketDTO.java b/api/src/main/java/market/guess/api/MarketDTO.java deleted file mode 100644 index b7c48a2..0000000 --- a/api/src/main/java/market/guess/api/MarketDTO.java +++ /dev/null @@ -1,3 +0,0 @@ -package market.guess.api; - -public record MarketDTO(String key, String name, String price, String volume) {} diff --git a/api/src/main/java/market/guess/api/MarketStateDTO.java b/api/src/main/java/market/guess/api/MarketStateDTO.java deleted file mode 100644 index da2fff0..0000000 --- a/api/src/main/java/market/guess/api/MarketStateDTO.java +++ /dev/null @@ -1,11 +0,0 @@ -package market.guess.api; - -import java.util.List; -import market.guess.model.event.MechanismType; - -public record MarketStateDTO( - String eventKey, - MechanismType mechanism, - List markets, - String accountBalance, - String commissionCollected) {} diff --git a/api/src/main/java/market/guess/api/PurchaseReceiptDTO.java b/api/src/main/java/market/guess/api/PurchaseReceiptDTO.java deleted file mode 100644 index 02e8007..0000000 --- a/api/src/main/java/market/guess/api/PurchaseReceiptDTO.java +++ /dev/null @@ -1,10 +0,0 @@ -package market.guess.api; - -import java.util.List; - -public record PurchaseReceiptDTO( - List trades, - String sharesCost, - String commissionPaid, - String totalPaid, - MarketStateDTO stateAfter) {} diff --git a/api/src/main/java/market/guess/api/TradeRowDTO.java b/api/src/main/java/market/guess/api/TradeRowDTO.java deleted file mode 100644 index 68d159a..0000000 --- a/api/src/main/java/market/guess/api/TradeRowDTO.java +++ /dev/null @@ -1,4 +0,0 @@ -package market.guess.api; - -public record TradeRowDTO( - String at, String userName, String optionName, String quantity, String pricePaid) {} diff --git a/api/src/main/java/market/guess/model/event/EventDetailDTO.java b/api/src/main/java/market/guess/model/event/EventDetailDTO.java index 9f59b53..f5c4edf 100644 --- a/api/src/main/java/market/guess/model/event/EventDetailDTO.java +++ b/api/src/main/java/market/guess/model/event/EventDetailDTO.java @@ -1,8 +1,8 @@ package market.guess.model.event; import java.util.List; -import market.guess.api.MarketStateDTO; -import market.guess.api.TradeRowDTO; +import market.guess.model.market.MarketStateDTO; +import market.guess.model.market.TradeRowDTO; public record EventDetailDTO( EventSummaryDTO summary, diff --git a/api/src/main/java/market/guess/model/ledger/LedgerDTO.java b/api/src/main/java/market/guess/model/ledger/LedgerDTO.java new file mode 100644 index 0000000..d527c12 --- /dev/null +++ b/api/src/main/java/market/guess/model/ledger/LedgerDTO.java @@ -0,0 +1,6 @@ +package market.guess.model.ledger; + +import java.util.List; + +public record LedgerDTO( + String owner, String balance, boolean blocked, List entries) {} diff --git a/api/src/main/java/market/guess/model/market/MarketDTO.java b/api/src/main/java/market/guess/model/market/MarketDTO.java new file mode 100644 index 0000000..6b31375 --- /dev/null +++ b/api/src/main/java/market/guess/model/market/MarketDTO.java @@ -0,0 +1,3 @@ +package market.guess.model.market; + +public record MarketDTO(String key, String name, String price, String volume) {} diff --git a/api/src/main/java/market/guess/model/market/MarketStateDTO.java b/api/src/main/java/market/guess/model/market/MarketStateDTO.java new file mode 100644 index 0000000..3e9b967 --- /dev/null +++ b/api/src/main/java/market/guess/model/market/MarketStateDTO.java @@ -0,0 +1,11 @@ +package market.guess.model.market; + +import java.util.List; +import market.guess.model.event.MechanismType; + +public record MarketStateDTO( + String eventKey, + MechanismType mechanism, + List markets, + String accountBalance, + String commissionCollected) {} diff --git a/api/src/main/java/market/guess/model/market/PurchaseReceiptDTO.java b/api/src/main/java/market/guess/model/market/PurchaseReceiptDTO.java new file mode 100644 index 0000000..0341542 --- /dev/null +++ b/api/src/main/java/market/guess/model/market/PurchaseReceiptDTO.java @@ -0,0 +1,10 @@ +package market.guess.model.market; + +import java.util.List; + +public record PurchaseReceiptDTO( + List trades, + String sharesCost, + String commissionPaid, + String totalPaid, + MarketStateDTO stateAfter) {} diff --git a/api/src/main/java/market/guess/model/market/TradeRowDTO.java b/api/src/main/java/market/guess/model/market/TradeRowDTO.java new file mode 100644 index 0000000..d3053b3 --- /dev/null +++ b/api/src/main/java/market/guess/model/market/TradeRowDTO.java @@ -0,0 +1,4 @@ +package market.guess.model.market; + +public record TradeRowDTO( + String at, String userName, String optionName, String quantity, String pricePaid) {} diff --git a/service/src/main/java/market/guess/service/LocalGuessMarketContext.java b/service/src/main/java/market/guess/service/LocalGuessMarketContext.java index f04324b..c85dadf 100644 --- a/service/src/main/java/market/guess/service/LocalGuessMarketContext.java +++ b/service/src/main/java/market/guess/service/LocalGuessMarketContext.java @@ -3,10 +3,10 @@ package market.guess.service; import java.math.BigDecimal; import java.time.Instant; import market.guess.api.GuessMarketContext; -import market.guess.api.PurchaseReceiptDTO; import market.guess.api.Result; -import market.guess.api.TradeRowDTO; import market.guess.model.event.EventDetailDTO; +import market.guess.model.market.PurchaseReceiptDTO; +import market.guess.model.market.TradeRowDTO; import market.guess.service.catalog.infrastructure.MarketContext; import market.guess.service.domain.Order; import market.guess.service.fulfillment.FulfillmentContext; diff --git a/service/src/main/java/market/guess/service/catalog/infrastructure/adapter/LedgerMapper.java b/service/src/main/java/market/guess/service/catalog/infrastructure/adapter/LedgerMapper.java new file mode 100644 index 0000000..5a46540 --- /dev/null +++ b/service/src/main/java/market/guess/service/catalog/infrastructure/adapter/LedgerMapper.java @@ -0,0 +1,10 @@ +package market.guess.service.catalog.infrastructure.adapter; + +import market.guess.model.ledger.LedgerDTO; +import market.guess.service.ledger.Ledger; +import org.mapstruct.Mapper; + +@Mapper +public interface LedgerMapper { + LedgerDTO ledgerToLedgerDTO(Ledger ledger); +} diff --git a/service/src/main/java/market/guess/service/catalog/infrastructure/mapper/v2/LedgerMapper.java b/service/src/main/java/market/guess/service/catalog/infrastructure/mapper/v2/LedgerMapper.java deleted file mode 100644 index fe0ea38..0000000 --- a/service/src/main/java/market/guess/service/catalog/infrastructure/mapper/v2/LedgerMapper.java +++ /dev/null @@ -1,11 +0,0 @@ -package market.guess.service.catalog.infrastructure.mapper.v2; - -import market.guess.api.AccountDTO; -import market.guess.service.ledger.Ledger; -import org.mapstruct.Mapper; - -@Mapper -public interface LedgerMapper { - - AccountDTO ledgerToLedgerDTO(Ledger account); -} diff --git a/service/src/main/java/market/guess/service/domain/Event.java b/service/src/main/java/market/guess/service/domain/Event.java index 1e17457..4517a4e 100644 --- a/service/src/main/java/market/guess/service/domain/Event.java +++ b/service/src/main/java/market/guess/service/domain/Event.java @@ -4,13 +4,13 @@ import java.math.BigDecimal; import java.time.Instant; import java.util.ArrayList; import java.util.List; -import market.guess.api.MarketDTO; -import market.guess.api.MarketStateDTO; -import market.guess.api.TradeRowDTO; import market.guess.model.event.CommissionTiming; import market.guess.model.event.EventStatus; import market.guess.model.event.EventSummaryDTO; import market.guess.model.ledger.LedgerType; +import market.guess.model.market.MarketDTO; +import market.guess.model.market.MarketStateDTO; +import market.guess.model.market.TradeRowDTO; import market.guess.service.helpers.BigDecimalOptions; import market.guess.service.helpers.InstantOptions; import market.guess.service.ledger.Ledger; diff --git a/service/src/main/java/market/guess/service/domain/Market.java b/service/src/main/java/market/guess/service/domain/Market.java index 3ff7e2d..c5960e3 100644 --- a/service/src/main/java/market/guess/service/domain/Market.java +++ b/service/src/main/java/market/guess/service/domain/Market.java @@ -1,7 +1,7 @@ package market.guess.service.domain; import java.math.BigDecimal; -import market.guess.api.MarketDTO; +import market.guess.model.market.MarketDTO; public final class Market { private final String key; diff --git a/service/src/test/java/market/guess/service/catalog/infrastructure/adapter/LedgerMapperTest.java b/service/src/test/java/market/guess/service/catalog/infrastructure/adapter/LedgerMapperTest.java new file mode 100644 index 0000000..976442c --- /dev/null +++ b/service/src/test/java/market/guess/service/catalog/infrastructure/adapter/LedgerMapperTest.java @@ -0,0 +1,113 @@ +package market.guess.service.catalog.infrastructure.adapter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.math.BigDecimal; +import java.time.Instant; +import java.util.List; +import market.guess.model.ledger.LedgerDTO; +import market.guess.model.ledger.LedgerEntryDTO; +import market.guess.model.ledger.LedgerType; +import market.guess.service.ledger.Ledger; +import market.guess.service.ledger.LedgerEntry; +import org.junit.Test; +import org.mapstruct.factory.Mappers; + +public class LedgerMapperTest { + + private final LedgerMapper mapper = Mappers.getMapper(LedgerMapper.class); + + @Test + public void nullLedgerMapsToNull() { + assertNull(mapper.ledgerToLedgerDTO(null)); + } + + @Test + public void mapsOwnerAndBalanceAsStrings() { + Ledger ledger = new Ledger("alice", new BigDecimal("100")); + + LedgerDTO dto = mapper.ledgerToLedgerDTO(ledger); + + assertEquals("alice", dto.owner()); + assertEquals("100.00", dto.balance()); + } + + @Test + public void emptyEntriesMapToEmptyList() { + Ledger ledger = new Ledger("alice", new BigDecimal("0")); + + LedgerDTO dto = mapper.ledgerToLedgerDTO(ledger); + + assertTrue(dto.entries().isEmpty()); + } + + @Test + public void mapsEntryFieldsInOrder() { + Ledger ledger = new Ledger("bob", new BigDecimal("0")); + ledger.record( + new LedgerEntry( + 1, + Instant.parse("2026-01-01T00:00:00Z"), + LedgerType.DEPOSIT, + new BigDecimal("50.00"), + new BigDecimal("50.00"), + "first")); + ledger.record( + new LedgerEntry( + 2, + Instant.parse("2026-01-02T00:00:00Z"), + LedgerType.PURCHASE, + new BigDecimal("-20.00"), + new BigDecimal("30.00"), + "second")); + + List entries = mapper.ledgerToLedgerDTO(ledger).entries(); + + assertEquals(2, entries.size()); + LedgerEntryDTO first = entries.get(0); + assertEquals(LedgerType.DEPOSIT, first.type()); + assertEquals("50.00", first.amount()); + assertEquals("50.00", first.balanceAfter()); + assertEquals("first", first.note()); + LedgerEntryDTO second = entries.get(1); + assertEquals(LedgerType.PURCHASE, second.type()); + assertEquals("-20.00", second.amount()); + assertEquals("30.00", second.balanceAfter()); + assertEquals("second", second.note()); + } + + @Test + public void nullAmountAndBalanceAfterMapToNullStrings() { + Ledger ledger = new Ledger("carol", new BigDecimal("0")); + ledger.record(new LedgerEntry(1, Instant.now(), LedgerType.REFUND, null, null, null)); + + LedgerEntryDTO entry = mapper.ledgerToLedgerDTO(ledger).entries().get(0); + + assertNull(entry.amount()); + assertNull(entry.balanceAfter()); + } + + /** + * LedgerEntry.id/time and Ledger's account-blocked state have no matching AccountDTO/ + * LedgerEntryDTO source property, so MapStruct leaves them at their Java defaults. This pins that + * known gap; once the mapper is taught to fill seq/at/blocked, update these assertions instead of + * deleting them. + */ + @Test + public void unmappedTargetPropertiesFallBackToDefaults() { + Ledger ledger = new Ledger("dave", new BigDecimal("0")); + ledger.record( + new LedgerEntry( + 7, Instant.now(), LedgerType.COMMISSION, BigDecimal.ONE, BigDecimal.ONE, "n")); + + LedgerDTO dto = mapper.ledgerToLedgerDTO(ledger); + + assertFalse(dto.blocked()); + LedgerEntryDTO entry = dto.entries().get(0); + assertEquals(0L, entry.seq()); + assertNull(entry.at()); + } +} diff --git a/service/src/test/java/market/guess/service/catalog/infrastructure/mapper/v2/LedgerMapperTest.java b/service/src/test/java/market/guess/service/catalog/infrastructure/mapper/v2/LedgerMapperTest.java deleted file mode 100644 index 9e00411..0000000 --- a/service/src/test/java/market/guess/service/catalog/infrastructure/mapper/v2/LedgerMapperTest.java +++ /dev/null @@ -1,103 +0,0 @@ -package market.guess.service.catalog.infrastructure.mapper.v2; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.math.BigDecimal; -import java.time.Instant; -import java.util.List; -import market.guess.api.AccountDTO; -import market.guess.model.ledger.LedgerEntryDTO; -import market.guess.model.ledger.LedgerType; -import market.guess.service.ledger.Ledger; -import market.guess.service.ledger.LedgerEntry; -import org.junit.Test; -import org.mapstruct.factory.Mappers; - -public class LedgerMapperTest { - - private final LedgerMapper mapper = Mappers.getMapper(LedgerMapper.class); - - @Test - public void nullLedgerMapsToNull() { - assertNull(mapper.ledgerToLedgerDTO(null)); - } - - @Test - public void mapsOwnerAndBalanceAsStrings() { - Ledger ledger = new Ledger("alice", new BigDecimal("100")); - - AccountDTO dto = mapper.ledgerToLedgerDTO(ledger); - - assertEquals("alice", dto.owner()); - assertEquals("100.00", dto.balance()); - } - - @Test - public void emptyEntriesMapToEmptyList() { - Ledger ledger = new Ledger("alice", new BigDecimal("0")); - - AccountDTO dto = mapper.ledgerToLedgerDTO(ledger); - - assertTrue(dto.entries().isEmpty()); - } - - @Test - public void mapsEntryFieldsInOrder() { - Ledger ledger = new Ledger("bob", new BigDecimal("0")); - ledger.record( - new LedgerEntry( - 1, Instant.parse("2026-01-01T00:00:00Z"), LedgerType.DEPOSIT, - new BigDecimal("50.00"), new BigDecimal("50.00"), "first")); - ledger.record( - new LedgerEntry( - 2, Instant.parse("2026-01-02T00:00:00Z"), LedgerType.PURCHASE, - new BigDecimal("-20.00"), new BigDecimal("30.00"), "second")); - - List entries = mapper.ledgerToLedgerDTO(ledger).entries(); - - assertEquals(2, entries.size()); - LedgerEntryDTO first = entries.get(0); - assertEquals(LedgerType.DEPOSIT, first.type()); - assertEquals("50.00", first.amount()); - assertEquals("50.00", first.balanceAfter()); - assertEquals("first", first.note()); - LedgerEntryDTO second = entries.get(1); - assertEquals(LedgerType.PURCHASE, second.type()); - assertEquals("-20.00", second.amount()); - assertEquals("30.00", second.balanceAfter()); - assertEquals("second", second.note()); - } - - @Test - public void nullAmountAndBalanceAfterMapToNullStrings() { - Ledger ledger = new Ledger("carol", new BigDecimal("0")); - ledger.record(new LedgerEntry(1, Instant.now(), LedgerType.REFUND, null, null, null)); - - LedgerEntryDTO entry = mapper.ledgerToLedgerDTO(ledger).entries().get(0); - - assertNull(entry.amount()); - assertNull(entry.balanceAfter()); - } - - /** - * LedgerEntry.id/time and Ledger's account-blocked state have no matching AccountDTO/ - * LedgerEntryDTO source property, so MapStruct leaves them at their Java defaults. This - * pins that known gap; once the mapper is taught to fill seq/at/blocked, update these - * assertions instead of deleting them. - */ - @Test - public void unmappedTargetPropertiesFallBackToDefaults() { - Ledger ledger = new Ledger("dave", new BigDecimal("0")); - ledger.record(new LedgerEntry(7, Instant.now(), LedgerType.COMMISSION, BigDecimal.ONE, BigDecimal.ONE, "n")); - - AccountDTO dto = mapper.ledgerToLedgerDTO(ledger); - - assertFalse(dto.blocked()); - LedgerEntryDTO entry = dto.entries().get(0); - assertEquals(0L, entry.seq()); - assertNull(entry.at()); - } -} diff --git a/tools/_util.sh b/tools/_util.sh index fde4797..a041f2d 100644 --- a/tools/_util.sh +++ b/tools/_util.sh @@ -5,15 +5,18 @@ case "$(uname -s)" in *) SEP=":" ;; esac -MODULES="api service ui-console" +MODULES="api service ui-console ui-desktop" DEPS_api="" DEPS_service="api" DEPS_ui_console="api service" +DEPS_ui_desktop="" -RUNTIME_LIB_DIRS="pico jaxb gson" +RUNTIME_LIB_DIRS="pico jaxb gson openjfx" -MAIN_CLASS="market.guess.ui.console.App" +EXECUTABLES="ui-console ui-desktop" +MAINCLASS_ui_console="market.guess.ui.console.App" +MAINCLASS_ui_desktop="market.guess.ui.desktop.Launcher" JAVA_HOME_DIR=$(java -XshowSettings:properties -version 2>&1 | tr -d '\r' | sed -n 's/^ *java\.home = //p') case "$(uname -s)" in @@ -45,6 +48,24 @@ deps_of() { eval "printf '%s' \"\${$v}\"" } +mainclass_of() { + local v="MAINCLASS_$(echo "$1" | tr '-' '_')" + eval "printf '%s' \"\${$v}\"" +} + +# JAR manifest lines are capped at 72 bytes; a raw "Key: value" line trips +# `line too long` once enough jars are on the Class-Path (openjfx pushed us +# over it). Fold per spec: continuation lines start with a single space. +write_manifest_attr() { + local file="$1" line="$2: $3" + : >"$file" + while [ "${#line}" -gt 72 ]; do + printf '%s\n' "${line:0:72}" >>"$file" + line=" ${line:72}" + done + printf '%s\n\n' "$line" >>"$file" +} + module_cp() { local cp="" for d in "$@"; do cp="$cp${cp:+$SEP}build/classes/$d"; done diff --git a/tools/package.sh b/tools/package.sh index a85ee6c..186dab5 100644 --- a/tools/package.sh +++ b/tools/package.sh @@ -22,63 +22,74 @@ for d in $RUNTIME_LIB_DIRS; do echo " lib/$d/ ($n jars)" done -echo "=== Generating console manifest ===" +echo "=== Generating executable manifests ===" # Generated from what is actually staged, never hand-maintained. Four silent # failure modes: wildcards match nothing; a missing trailing newline makes jar # drop the line; paths are relative to this jar; and java -jar ignores -cp, so # this line is the entire classpath at runtime. -MF="$TMP/console-manifest.txt" -CPLINE="" -for m in $MODULES; do - [ "$m" = ui-console ] && continue - CPLINE="$CPLINE${CPLINE:+ }$m.jar" -done -for d in $RUNTIME_LIB_DIRS; do - for j in "$DIST"/lib/"$d"/*.jar; do - [ -f "$j" ] || continue - CPLINE="$CPLINE lib/$d/$(basename "$j")" +for e in $EXECUTABLES; do + CPLINE="" + for m in $MODULES; do + [ "$m" = "$e" ] && continue + CPLINE="$CPLINE${CPLINE:+ }$m.jar" + done + for d in $RUNTIME_LIB_DIRS; do + for j in "$DIST"/lib/"$d"/*.jar; do + [ -f "$j" ] || continue + CPLINE="$CPLINE lib/$d/$(basename "$j")" + done done + write_manifest_attr "$TMP/$e-manifest.txt" "Class-Path" "$CPLINE" + echo " $e: $CPLINE" done -printf 'Class-Path: %s\n\n' "$CPLINE" >"$MF" -echo " $CPLINE" echo "=== Packaging ===" for m in $MODULES; do - if [ "$m" = ui-console ]; then - "$JAR" --create --file "$DIST/$m.jar" \ - --main-class "$MAIN_CLASS" --manifest "$MF" -C "build/classes/$m" . - else + case " $EXECUTABLES " in + *" $m "*) + "$JAR" --create --file "$DIST/$m.jar" --main-class "$(mainclass_of "$m")" \ + --manifest "$TMP/$m-manifest.txt" -C "build/classes/$m" . + ;; + *) "$JAR" --create --file "$DIST/$m.jar" -C "build/classes/$m" . - fi + ;; + esac echo " $DIST/$m.jar" done -cat >"$DIST/run.bat" <<'EOF' +for e in $EXECUTABLES; do + cat >"$DIST/run-${e#ui-}.bat" <