Skip to content

Commit 9afa76e

Browse files
Removed dependency on rune.common
Updated CDM build script to optionally skip downloading CDM Updated release notes
1 parent f3b8e6f commit 9afa76e

File tree

4 files changed

+83
-139
lines changed

4 files changed

+83
-139
lines changed

RELEASE.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,19 @@
22

33
_What is being released?_
44

5-
This release adds support for meta data and for serialization / deserialization consistent with the [serialization specifications in CDM issue #3236](https://github.com/finos/common-domain-model/issues/3236)
5+
This release adds support for metadata and for serialization / deserialization consistent with the [serialization specifications in CDM issue #3236](https://github.com/finos/common-domain-model/issues/3236)
66

77
Also included is support for:
88

99
- circular Type definitions
1010
- increased testing of operators
1111
- generating Python across multiple namespaces
12+
- Command line (CLI) generation of Python from a Rune source file or directory. To execute the CLI (assuming
13+
the default process wherein the JAR is built in the target directory):
14+
15+
```bash
16+
java -cp target/python-0.0.0.main-SNAPSHOT.jar com.regnosys.rosetta.generator.python.PythonCodeGeneratorCLI -s [rune source files] -t [target directory for generated Python]
17+
```
1218

1319
## Reading From and Writing To a String
1420

build/build_cdm.sh

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,32 +27,49 @@ if ! $PYEXE -c 'import sys; assert sys.version_info >= (3,11)' > /dev/null 2>&1;
2727
exit 1
2828
fi
2929

30-
MY_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
31-
cd ${MY_PATH} || error
30+
BUILD_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
31+
PROJECT_ROOT_PATH=$BUILD_PATH/..
32+
PYTHON_TARGET_PATH=$PROJECT_ROOT_PATH/target/python-cdm
33+
cd ${BUILD_PATH} || error
34+
35+
# Parse command-line arguments for --skip-cdm
36+
SKIP_CDM=0
37+
for arg in "$@"; do
38+
if [[ "$arg" == "--skip-cdm" ]]; then
39+
SKIP_CDM=1
40+
fi
41+
done
42+
43+
if [[ $SKIP_CDM -eq 0 ]]; then
44+
source $BUILD_PATH/get_cdm.sh
45+
else
46+
echo "Skipping get_cdm.sh as requested."
47+
fi
3248

33-
source $MY_PATH/../build/get_cdm.sh
3449
echo "***** build CDM"
35-
cd $MY_PATH/..
36-
mvn clean install
50+
java -cp $PROJECT_ROOT_PATH/target/python-0.0.0.main-SNAPSHOT.jar com.regnosys.rosetta.generator.python.PythonCodeGeneratorCLI -s $BUILD_PATH//common-domain-model/rosetta-source/src/main/rosetta/ -t $PYTHON_TARGET_PATH
51+
JAVA_EXIT_CODE=$?
52+
if [[ $JAVA_EXIT_CODE -eq 1 ]]; then
53+
echo "Java program returned exit code 1. Stopping script."
54+
exit 1
55+
fi
56+
3757
echo "***** setting up common environment"
38-
BUILDPATH="../build"
39-
source $MY_PATH/$BUILDPATH/setup_python_env.sh
58+
source $BUILD_PATH/setup_python_env.sh
4059

4160
echo "***** activating virtual environment"
4261
VENV_NAME=".pyenv"
43-
VENV_PATH=".."
44-
source $MY_PATH/$BUILDPATH/$VENV_PATH/$VENV_NAME/${PY_SCRIPTS}/activate || error
62+
source $PROJECT_ROOT_PATH/$VENV_NAME/${PY_SCRIPTS}/activate || error
4563

4664
echo "***** build CDM Python package"
47-
PYTHONSOURCEDIR=$MY_PATH/"../target/python-cdm"
48-
cd $PYTHONSOURCEDIR
65+
cd $PYTHON_TARGET_PATH
4966
rm python_cdm-*.*.*-py3-none-any.whl
5067
$PYEXE -m pip wheel --no-deps --only-binary :all: . || processError
5168

5269
echo "***** cleanup"
5370

5471
deactivate
55-
source $MY_PATH/$BUILDPATH/cleanup_python_env.sh
72+
source $BUILD_PATH/cleanup_python_env.sh
5673

5774
echo ""
5875
echo ""

pom.xml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@
8282
<stagingTimeoutInMinutes>20</stagingTimeoutInMinutes>
8383

8484
<rosetta.dsl.version>9.63.0</rosetta.dsl.version>
85-
<rosetta.bundle.version>11.75.0</rosetta.bundle.version>
8685

8786
<xtext.version>2.38.0</xtext.version>
8887
<guice.version>6.0.0</guice.version>
@@ -107,6 +106,7 @@
107106
<maven-dependency-plugin.version>3.1.1</maven-dependency-plugin.version>
108107
<nexus-staging-maven-plugin.version>1.6.13</nexus-staging-maven-plugin.version>
109108
<maven-gpg-plugin.version>3.2.4</maven-gpg-plugin.version>
109+
<maven-resources-plugin.version>3.3.1</maven-resources-plugin.version>
110110
<!-- Used by the Python generator -->
111111
<cdm.rosetta.source.path>build/common-domain-model/rosetta-source/src/main/rosetta</cdm.rosetta.source.path>
112112
<cdm.python.output.path>target/python-cdm</cdm.python.output.path>
@@ -285,11 +285,6 @@
285285
<artifactId>com.regnosys.rosetta.tests</artifactId>
286286
<scope>test</scope>
287287
</dependency>
288-
<dependency>
289-
<groupId>com.regnosys</groupId>
290-
<artifactId>rosetta-common</artifactId>
291-
<version>${rosetta.bundle.version}</version>
292-
</dependency>
293288
<dependency>
294289
<groupId>commons-io</groupId>
295290
<artifactId>commons-io</artifactId>

src/main/java/com/regnosys/rosetta/generator/python/PythonCodeGeneratorCLI.java

Lines changed: 46 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,10 @@
66
import com.regnosys.rosetta.RosettaRuntimeModule;
77
import com.regnosys.rosetta.RosettaStandaloneSetup;
88
import com.regnosys.rosetta.builtin.RosettaBuiltinsService;
9-
import com.regnosys.rosetta.common.util.ClassPathUtils;
10-
import com.regnosys.rosetta.common.util.UrlUtils;
119
import com.regnosys.rosetta.generator.external.ExternalGenerator;
1210
import com.regnosys.rosetta.generator.external.ExternalGenerators;
1311
import com.regnosys.rosetta.rosetta.RosettaModel;
1412
import org.apache.commons.cli.*;
15-
import org.apache.commons.io.FileUtils;
1613
import org.eclipse.emf.ecore.resource.Resource;
1714
import org.eclipse.emf.ecore.resource.ResourceSet;
1815
import org.eclipse.xtext.resource.XtextResourceSet;
@@ -22,12 +19,10 @@
2219
import org.slf4j.LoggerFactory;
2320

2421
import jakarta.inject.Inject;
25-
import java.io.File;
2622
import java.io.IOException;
2723
import java.nio.file.*;
2824
import java.util.*;
2925
import java.util.stream.Collectors;
30-
import java.util.stream.Stream;
3126

3227
/**
3328
* Command-line interface for generating Python code from Rosetta models.
@@ -92,7 +87,6 @@ public static void main(String[] args) {
9287
if (cmd.hasOption("s")) {
9388
String srcDir = cmd.getOptionValue("s");
9489
translateFromSourceDir(srcDir, tgtDir);
95-
translateFromSourceDir2(srcDir, tgtDir + "-2");
9690
} else if (cmd.hasOption("f")) {
9791
String srcFile = cmd.getOptionValue("f");
9892
translateFromSourceFile(srcFile, tgtDir);
@@ -111,132 +105,79 @@ private static void printUsage(Options options) {
111105
formatter.printHelp("PythonCodeGeneratorCLI", options, true);
112106
}
113107

114-
private static void translateFromSourceDir(String srcDir, String tgtDir) {
115-
LOGGER.info("Reading from directory: {} and writing to: {}", srcDir, tgtDir);
108+
private static void translateFromSourceDir (String srcDir, String tgtDir) {
109+
// Find all .rosetta files in a directory
116110
Path srcDirPath = Paths.get(srcDir);
117111
if (!Files.exists(srcDirPath)) {
118-
System.err.println("Source directory does not exist: " + srcDir);
119-
return;
112+
LOGGER.error("Source directory does not exist: {}", srcDir);
113+
System.exit(1);
120114
}
121115
if (!Files.isDirectory(srcDirPath)) {
122-
System.err.println("Source directory is not a directory: " + srcDir);
123-
return;
116+
LOGGER.error("Source directory is not a directory: {}", srcDir);
117+
System.exit(1);
124118
}
125-
List<Path> rosettaFiles = new ArrayList<>();
126-
try (Stream<Path> paths = Files.walk(srcDirPath)) {
127-
paths.filter(Files::isRegularFile)
128-
.filter(f -> f.getFileName().toString().endsWith(".rosetta"))
129-
.forEach(rosettaFiles::add);
130-
} catch (IOException e) {
131-
System.err.println("Error reading source directory: " + e.getMessage());
132-
return;
133-
}
134-
LOGGER.info("Found {} .rosetta files in directory {}", rosettaFiles.size(), srcDir);
135-
translateRosetta(rosettaFiles, tgtDir);
136-
}
137-
138-
private static void translateFromSourceDir2(String srcDir, String tgtDir) {
139-
LOGGER.info("translateFromSourceDir2 ... Reading from directory: {} and writing to: {}", srcDir, tgtDir);
140-
Path srcDirPath = Paths.get(srcDir);
141-
if (!Files.exists(srcDirPath)) {
142-
System.err.println("Source directory does not exist: " + srcDir);
143-
return;
144-
}
145-
if (!Files.isDirectory(srcDirPath)) {
146-
System.err.println("Source directory is not a directory: " + srcDir);
147-
return;
148-
}
149-
Injector injector = new PythonRosettaStandaloneSetup().createInjectorAndDoEMFRegistration();
150-
PythonCodeGenerator pythonCodeGenerator = injector.getInstance(PythonCodeGenerator.class);
151-
PythonModelLoader modelLoader = injector.getInstance(PythonModelLoader.class);
152-
ResourceSet resourceSet = injector.getInstance(ResourceSet.class);
153-
154-
List<Resource> resources = new LinkedList<>();
155-
156-
RosettaBuiltinsService builtins = injector.getInstance(RosettaBuiltinsService.class);
157-
resources.add (resourceSet.getResource(builtins.basicTypesURI, true));
158-
resources.add (resourceSet.getResource(builtins.annotationsURI, true));
159119
try {
160-
// Find all .rosetta files in the directory and load them from disk
161-
Files.walk(srcDirPath)
162-
.filter(path -> path.toString().endsWith(".rosetta"))
163-
.map(file -> resourceSet.getResource(URI.createFileURI(file.toString()), true))
164-
.forEach(resources::add);
120+
List<Path> rosettaFiles = Files.walk(srcDirPath)
121+
.filter(Files::isRegularFile)
122+
.filter(f -> f.getFileName().toString().endsWith(".rosetta"))
123+
.collect(Collectors.toList());
124+
processRosettaFiles(rosettaFiles, tgtDir);
165125
} catch (IOException e) {
166-
System.err.println("Error reading source directory: " + e.getMessage());
167-
return;
168-
}
169-
LOGGER.info("translateFromSourceDir2 ... Found {} .rosetta files in directory {}", resources.size(), srcDir);
170-
171-
172-
List<RosettaModel> models = modelLoader.rosettaModels2(resources);
173-
if (models.isEmpty()) {
174-
System.err.println("No valid Rosetta models found.");
175-
return;
176-
}
177-
String version = models.get(0).getVersion();
178-
179-
LOGGER.info("translateFromSourceDir2 ... Processing {} models, version: {}", models.size(), version);
180-
181-
Map<String, CharSequence> generatedPython = new HashMap<>();
182-
pythonCodeGenerator.beforeAllGenerate(resourceSet, models, version);
183-
for (RosettaModel model : models) {
184-
System.out.println("translateFromSourceDir2 ... processing: " + model.getName());
185-
generatedPython.putAll(pythonCodeGenerator.beforeGenerate(model.eResource(), model, version));
186-
generatedPython.putAll(pythonCodeGenerator.generate(model.eResource(), model, version));
187-
generatedPython.putAll(pythonCodeGenerator.afterGenerate(model.eResource(), model, version));
126+
LOGGER.error("Failed to process source directory: {}", srcDir, e);
188127
}
189-
generatedPython.putAll(pythonCodeGenerator.afterAllGenerate(resourceSet, models, version));
190-
191-
writePythonFiles(generatedPython, tgtDir);
192128
}
193-
194-
195-
private static void translateFromSourceFile(String srcFile, String tgtDir) {
196-
LOGGER.info("Reading from file: {} and writing to: {}", srcFile, tgtDir);
129+
private static void translateFromSourceFile (String srcFile, String tgtDir) {
197130
Path srcFilePath = Paths.get(srcFile);
198131
if (!Files.exists(srcFilePath)) {
199-
System.err.println("Source file does not exist: " + srcFile);
200-
return;
132+
LOGGER.error("Source file does not exist: {}", srcFile);
133+
System.exit(1);
201134
}
202135
if (Files.isDirectory(srcFilePath)) {
203-
System.err.println("Source file is a directory: " + srcFile);
204-
return;
136+
LOGGER.error("Source file is a directory: {}", srcFile);
137+
System.exit(1);
205138
}
206-
translateRosetta(Collections.singletonList(srcFilePath), tgtDir);
139+
if (!srcFilePath.toString().endsWith(".rosetta")) {
140+
LOGGER.error("Source file does not end with .rosetta: {}", srcFile);
141+
System.exit(1);
142+
}
143+
List<Path> rosettaFiles = List.of(srcFilePath);
144+
processRosettaFiles(rosettaFiles, tgtDir);
207145
}
146+
// Common processing function
147+
private static void processRosettaFiles(List<Path> rosettaFiles, String tgtDir) {
148+
LOGGER.info("Processing {} .rosetta files, writing to: {}", rosettaFiles.size(), tgtDir);
208149

209-
private static void translateRosetta(List<Path> rosettaFiles, String tgtDir) {
210-
LOGGER.info("Cleaning target directory: {}", tgtDir);
211-
File directory = new File(tgtDir);
212-
try {
213-
if (directory.exists() && directory.isDirectory()) {
214-
FileUtils.cleanDirectory(directory);
215-
}
216-
} catch (IOException e) {
217-
System.err.println("Failed to clean the directory: " + e.getMessage());
218-
return;
150+
if (rosettaFiles.isEmpty()) {
151+
System.err.println("No .rosetta files found to process.");
152+
System.exit(1);
219153
}
220154

221155
Injector injector = new PythonRosettaStandaloneSetup().createInjectorAndDoEMFRegistration();
156+
ResourceSet resourceSet = injector.getInstance(ResourceSet.class);
157+
List<Resource> resources = new LinkedList<>();
158+
RosettaBuiltinsService builtins = injector.getInstance(RosettaBuiltinsService.class);
159+
resources.add (resourceSet.getResource(builtins.basicTypesURI, true));
160+
resources.add (resourceSet.getResource(builtins.annotationsURI, true));
161+
rosettaFiles.stream()
162+
.map(path -> resourceSet.getResource(URI.createFileURI(path.toString()), true))
163+
.forEach(resources::add);
164+
222165
PythonCodeGenerator pythonCodeGenerator = injector.getInstance(PythonCodeGenerator.class);
223166
PythonModelLoader modelLoader = injector.getInstance(PythonModelLoader.class);
224167

225-
List<Path> staticRosettaFilePaths = ClassPathUtils.findStaticRosettaFilePaths();
226-
List<RosettaModel> models = modelLoader.rosettaModels(staticRosettaFilePaths, rosettaFiles);
168+
List<RosettaModel> models = modelLoader.getRosettaModels(resources);
227169
if (models.isEmpty()) {
228-
System.err.println("No valid Rosetta models found.");
229-
return;
170+
LOGGER.error("No valid Rosetta models found.");
171+
System.exit(1);
230172
}
231-
XtextResourceSet resourceSet = modelLoader.getResourceSet();
232-
String version = models.get(0).getVersion();
173+
String version = models.getFirst().getVersion();
233174

234175
LOGGER.info("Processing {} models, version: {}", models.size(), version);
235176

236177
Map<String, CharSequence> generatedPython = new HashMap<>();
237178
pythonCodeGenerator.beforeAllGenerate(resourceSet, models, version);
238179
for (RosettaModel model : models) {
239-
System.out.println("translateRosetta ... processing: " + model.getName());
180+
System.out.println("Processing: " + model.getName());
240181
generatedPython.putAll(pythonCodeGenerator.beforeGenerate(model.eResource(), model, version));
241182
generatedPython.putAll(pythonCodeGenerator.generate(model.eResource(), model, version));
242183
generatedPython.putAll(pythonCodeGenerator.afterGenerate(model.eResource(), model, version));
@@ -261,27 +202,12 @@ private static void writePythonFiles(Map<String, CharSequence> generatedPython,
261202
}
262203
LOGGER.info("Wrote {} files to {}", generatedPython.size(), tgtDir);
263204
}
264-
265205
// --- Helper classes for model loading and Guice setup ---
266206

267207
static class PythonModelLoader {
268208
@Inject Provider<XtextResourceSet> resourceSetProvider;
269-
270-
public List<RosettaModel> rosettaModels(List<Path> statics, List<Path> sourceFiles) {
271-
XtextResourceSet resourceSet = resourceSetProvider.get();
272-
return Stream.concat(statics.stream(), sourceFiles.stream())
273-
.map(UrlUtils::toUrl)
274-
.map(PythonModelLoader::url)
275-
.map(f -> getResource(resourceSet, f))
276-
.filter(Objects::nonNull)
277-
.map(Resource::getContents)
278-
.flatMap(Collection::stream)
279-
.filter(r -> r instanceof RosettaModel)
280-
.map(r -> (RosettaModel) r)
281-
.collect(Collectors.toList());
282-
}
283-
284-
public List<RosettaModel> rosettaModels2(List<Resource> resources) {
209+
210+
public List<RosettaModel> getRosettaModels(List<Resource> resources) {
285211
return resources.stream()
286212
.filter(Objects::nonNull)
287213
.map(Resource::getContents)
@@ -343,4 +269,4 @@ public Injector createInjector() {
343269
return Guice.createInjector(new PythonRosettaRuntimeModule());
344270
}
345271
}
346-
}
272+
}

0 commit comments

Comments
 (0)