blob: 36552a07764fc1d1cee0a57651eebff76de313e7 [file] [log] [blame]
Ray Milkeyad83ef92018-06-05 11:05:51 -07001#!/usr/bin/env python
2#FIXME Add license
3
4##### Templates for features.xml
5FEATURES_HEADER = '''\
6<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
7<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
8 name="%(feature_repo_name)s">
9'''
10FEATURE_HEADER= '''\
11 <feature name="%(feature_name)s" version="%(version)s"
12 description="%(title)s">
13'''
14EXISTING_FEATURE = ' <feature>%s</feature>\n'
15BUNDLE = ' <bundle>%s</bundle>\n'
16FEATURE_FOOTER = ' </feature>\n'
Ray Milkey1d52ddd2018-06-07 10:37:24 -070017FEATURES_FOOTER = '</features>\n'
Ray Milkeyad83ef92018-06-05 11:05:51 -070018
19##### Templates for app.xml
20APP_HEADER = '''\
21<?xml version="1.0" encoding="UTF-8"?>
22<app name="%(app_name)s" origin="%(origin)s" version="%(version)s"
23 title="%(title)s" category="%(category)s" url="%(url)s"
24 featuresRepo="%(feature_repo_name)s"
25 features="%(feature_name)s" apps="%(apps)s">
26 <description>%(description)s</description>
27'''
28ARTIFACT = ' <artifact>%s</artifact>\n'
29SECURITY = '''\
30 <security>
31%s
32 </security>\n'''
Ray Milkey1d52ddd2018-06-07 10:37:24 -070033APP_FOOTER = '</app>\n'
Ray Milkeyad83ef92018-06-05 11:05:51 -070034
35NON_OSGI_TAG = 'NON-OSGI'
36
37def mvnUrl(bundle):
38 #mvn-uri := 'mvn:' [ repository-url '!' ] group-id '/' artifact-id [ '/' [version] [ '/' [type] [ '/' classifier ] ] ] ]
Thomas Vachuska510419f2018-06-28 17:05:09 -070039 parts = bundle.split(':')[1:]
Ray Milkeyad83ef92018-06-05 11:05:51 -070040 prefix = 'mvn:'
41 suffix = ''
42 if len(parts) > 3:
43 parts.insert(2, parts.pop()) # move version to the 3rd position
44 if len(parts) >= 5:
45 # check classifier for special non-OSGi tag
46 i = parts[4].find(NON_OSGI_TAG)
47 if i == 0:
48 prefix = 'wrap:' + prefix
49 suffix = '$Bundle-SymbolicName=%s.%s&amp;Bundle-Version=%s' % tuple(parts[0:3])
50 if len(parts[4]) == len(NON_OSGI_TAG):
51 parts.pop() # pop off empty classifier
52 if parts[3].lower() == 'jar':
53 parts.pop() # pop off default extension: jar
54 else:
55 parts[4] = parts[4][len(NON_OSGI_TAG):]
56 return prefix + '/'.join(parts) + suffix
57
58def generateFeatureFile(feature_repo_name,
59 features = [],
60 **kwargs):
61 values = {
62 'feature_repo_name' : '-'.join(feature_repo_name.split(':')[1:3]),
63 }
64
65 output = FEATURES_HEADER % values
66
67 for feature in features:
68 output += feature
69
70 output += FEATURES_FOOTER
71 return output
72
73def generateFeature(feature_name,
74 version,
75 title,
76 features = [],
77 bundles = [],
78 **kwargs):
79 values = {
80 'feature_name' : feature_name,
81 'version' : version,
82 'title' : title,
83 }
84
85 output = FEATURE_HEADER % values
86
87 if features:
88 for feature in features:
89 output += EXISTING_FEATURE % feature
90
91 if bundles:
92 for bundle in bundles:
93 output += BUNDLE % mvnUrl(bundle)
94
95 output += FEATURE_FOOTER
96 return output
97
98
99def generateAppFile(app_name,
100 origin,
101 version,
102 title,
103 category,
104 url,
105 feature_repo_name,
106 feature_name,
107 description = None,
108 apps = [],
109 artifacts = [],
110 security= None,
111 **kwargs):
112 values = {
113 'app_name' : app_name,
114 'origin' : origin,
115 'version' : version,
116 'title' : title,
117 'category' : category,
118 'url' : url,
119 'feature_repo_name' : mvnUrl(feature_repo_name) + '/xml/features',
120 'feature_name' : feature_name,
121 }
122
123 values['description'] = description if description else title
124 values['apps'] = ','.join(apps) if apps else ''
125
126 output = APP_HEADER % values
127
128 for artifact in artifacts:
129 output += ARTIFACT % mvnUrl(artifact)
130
131 if security is not None:
132 output += SECURITY % security
133
134 output += APP_FOOTER
135 return output
136
Thomas Vachuskaaab45d12018-06-05 16:39:46 -0700137def write(name, msg):
138 if name is not None:
139 with open(name, "w") as file:
140 file.write(msg)
141 else:
142 print msg
Ray Milkeyad83ef92018-06-05 11:05:51 -0700143
144if __name__ == '__main__':
145 import sys, optparse
146
147 parser = optparse.OptionParser()
Thomas Vachuskaaab45d12018-06-05 16:39:46 -0700148 parser.add_option("-O", "--output", dest="output", help="Output file")
Ray Milkeyad83ef92018-06-05 11:05:51 -0700149 parser.add_option("-n", "--name", dest="feature_coords", help="Feature MVN Coords")
150 parser.add_option("-a", "--app", dest="app_name", help="App Name")
151 parser.add_option("-o", "--origin", dest="origin", help="Origin")
152 parser.add_option("-c", "--category", dest="category", help="Category")
153 parser.add_option("-u", "--url", dest="url", help="URL")
154 parser.add_option("-v", "--version", dest="version", help="Version")
155 parser.add_option("-t", "--title", dest="title", help="Title")
156 parser.add_option("-r", "--repo", dest="repo_name", help="Repo Name")
157 parser.add_option('-D', '--desc', dest='desc', help='Application description')
158 parser.add_option('-s', '--security', dest='security', help='Application security')
159
160 parser.add_option('-b', '--bundle',
161 action="append", dest='included_bundles',
162 metavar="BUNDLE", help='Included Bundle (multiple allowed)')
163 parser.add_option('-e', '--excluded-bundle',
164 action="append", dest='excluded_bundles',
165 metavar="BUNDLE", help='Excluded Bundle (multiple allowed)')
166 parser.add_option('-f', '--feature',
167 action="append", dest='features',
168 metavar="FEATURE", help='Existing Feature (multiple allowed)')
169 parser.add_option('-d', '--apps',
170 action="append", dest='apps',
171 metavar="FEATURE", help='Required App (multiple allowed)')
172
173 parser.add_option("-A", "--write-app", dest="write_app", action="store_true")
174 parser.add_option("-F", "--write-features", dest="write_features", action="store_true")
175 parser.add_option("-E", "--write-feature", dest="write_feature", action="store_true")
176
177 (options, args) = parser.parse_args()
178
179 values = {}
180 if options.feature_coords and options.version and options.title:
181 parts = options.feature_coords.split(':')
182 values['feature_name'] = parts[1] if len(parts) > 1 else parts[0]
183 values['version'] = options.version
184 values['title'] = options.title
185 else:
186 sys.stderr.write('ERROR: Feature Name, Version, and Title are required\n')
187 sys.stderr.flush()
188 sys.exit(1)
189
190 if options.app_name and options.origin and options.category and options.url:
191 values['app_name'] = options.app_name
192 values['origin'] = options.origin
193 values['category'] = options.category
194 values['url'] = options.url
195 elif options.write_app:
196 sys.stderr.write('ERROR: Feature Name, Version, and Title are required\n')
197 sys.stderr.flush()
198 sys.exit(1)
199
200 values['feature_repo_name'] = options.repo_name if options.repo_name \
201 else options.feature_coords
202
203 bundles = []
204 if options.included_bundles:
205 bundles += options.included_bundles
206 if options.excluded_bundles:
207 bundles += options.excluded_bundles
208 if options.desc:
209 values['description'] = options.desc
210
211 feature = generateFeature(bundles=bundles,
212 features=options.features,
213 **values)
214
215 if options.write_feature:
Thomas Vachuskaaab45d12018-06-05 16:39:46 -0700216 write(options.output, feature)
Ray Milkeyad83ef92018-06-05 11:05:51 -0700217
218 if options.write_features:
Thomas Vachuskaaab45d12018-06-05 16:39:46 -0700219 write(options.output,
220 generateFeatureFile(features=[ feature ], **values))
Ray Milkeyad83ef92018-06-05 11:05:51 -0700221
222 if options.write_app:
Thomas Vachuskaaab45d12018-06-05 16:39:46 -0700223 write(options.output,
224 generateAppFile(artifacts=options.included_bundles,
Ray Milkeyad83ef92018-06-05 11:05:51 -0700225 apps=options.apps,
226 security=options.security,
Thomas Vachuskaaab45d12018-06-05 16:39:46 -0700227 **values))