blob: dc2e5fa47362db01dea3db3d5dd40136767176e3 [file] [log] [blame]
Brian O'Connor1f165982016-04-06 21:36:09 -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'
17FEATURES_FOOTER = '</features>'
18
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'
29APP_FOOTER = '</app>'
30
Brian O'Connorbd6305a2016-04-25 14:28:12 -070031NON_OSGI_TAG = 'NON-OSGI'
Brian O'Connor1f165982016-04-06 21:36:09 -070032
33def mvnUrl(bundle):
Brian O'Connorbd6305a2016-04-25 14:28:12 -070034 #mvn-uri := 'mvn:' [ repository-url '!' ] group-id '/' artifact-id [ '/' [version] [ '/' [type] [ '/' classifier ] ] ] ]
35 parts = bundle.split(':')
36 prefix = 'mvn:'
37 suffix = ''
38 if len(parts) > 3:
39 parts.insert(2, parts.pop()) # move version to the 3rd position
40 if len(parts) >= 5:
41 # check classifier for special non-OSGi tag
42 i = parts[4].find(NON_OSGI_TAG)
43 if i == 0:
44 prefix = 'wrap:' + prefix
45 suffix = '$Bundle-SymbolicName=%s.%s&amp;Bundle-Version=%s' % tuple(parts[0:3])
46 if len(parts[4]) == len(NON_OSGI_TAG):
47 parts.pop() # pop off empty classifier
48 if parts[3].lower() == 'jar':
49 parts.pop() # pop off default extension: jar
50 else:
51 parts[4] = parts[4][len(NON_OSGI_TAG):]
52 return prefix + '/'.join(parts) + suffix
Brian O'Connor1f165982016-04-06 21:36:09 -070053
Brian O'Connorfc7f5fc2016-04-29 17:04:06 -070054def generateFeatureFile(feature_repo_name,
Brian O'Connor1f165982016-04-06 21:36:09 -070055 features = [],
Brian O'Connor1f165982016-04-06 21:36:09 -070056 **kwargs):
57 values = {
Brian O'Connorfc7f5fc2016-04-29 17:04:06 -070058 'feature_repo_name' : '-'.join(feature_repo_name.split(':')[1:3]),
59 }
60
61 output = FEATURES_HEADER % values
62
63 for feature in features:
64 output += feature
65
66 output += FEATURES_FOOTER
67 return output
68
69def generateFeature(feature_name,
70 version,
71 title,
72 features = [],
73 bundles = [],
74 **kwargs):
75 values = {
Brian O'Connor1f165982016-04-06 21:36:09 -070076 'feature_name' : feature_name,
77 'version' : version,
78 'title' : title,
Brian O'Connor1f165982016-04-06 21:36:09 -070079 }
80
Brian O'Connorfc7f5fc2016-04-29 17:04:06 -070081 output = FEATURE_HEADER % values
Brian O'Connor1f165982016-04-06 21:36:09 -070082
Brian O'Connorfc7f5fc2016-04-29 17:04:06 -070083 if features:
84 for feature in features:
85 output += EXISTING_FEATURE % feature
Brian O'Connor1f165982016-04-06 21:36:09 -070086
Brian O'Connorfc7f5fc2016-04-29 17:04:06 -070087 if bundles:
88 for bundle in bundles:
89 output += BUNDLE % mvnUrl(bundle)
Brian O'Connor1f165982016-04-06 21:36:09 -070090
Brian O'Connorfc7f5fc2016-04-29 17:04:06 -070091 output += FEATURE_FOOTER
Brian O'Connor1f165982016-04-06 21:36:09 -070092 return output
93
Brian O'Connorfc7f5fc2016-04-29 17:04:06 -070094
Brian O'Connor1f165982016-04-06 21:36:09 -070095def generateAppFile(app_name,
96 origin,
97 version,
98 title,
99 category,
100 url,
101 feature_repo_name,
102 feature_name,
103 description = None,
104 apps = [],
105 artifacts = [],
106 **kwargs):
107 values = {
108 'app_name' : app_name,
109 'origin' : origin,
110 'version' : version,
111 'title' : title,
112 'category' : category,
113 'url' : url,
114 'feature_repo_name' : mvnUrl(feature_repo_name) + '/xml/features',
115 'feature_name' : feature_name,
116 }
117
118 values['description'] = description if description else title
119 values['apps'] = ','.join(apps) if apps else ''
120
121 output = APP_HEADER % values
122
123 for artifact in artifacts:
124 output += ARTIFACT % mvnUrl(artifact)
125
126 output += APP_FOOTER
127 return output
128
129
130if __name__ == '__main__':
131 import sys, optparse
132
133 parser = optparse.OptionParser()
Brian O'Connore124f3d2016-04-06 23:54:26 -0700134 parser.add_option("-n", "--name", dest="feature_coords", help="Feature MVN Coords")
Brian O'Connor1f165982016-04-06 21:36:09 -0700135 parser.add_option("-a", "--app", dest="app_name", help="App Name")
136 parser.add_option("-o", "--origin", dest="origin", help="Origin")
137 parser.add_option("-c", "--category", dest="category", help="Category")
138 parser.add_option("-u", "--url", dest="url", help="URL")
139 parser.add_option("-v", "--version", dest="version", help="Version")
140 parser.add_option("-t", "--title", dest="title", help="Title")
141 parser.add_option("-r", "--repo", dest="repo_name", help="Repo Name")
142
143 parser.add_option('-b', '--bundle',
144 action="append", dest='included_bundles',
145 metavar="BUNDLE", help='Included Bundle (multiple allowed)')
146 parser.add_option('-e', '--excluded-bundle',
147 action="append", dest='excluded_bundles',
148 metavar="BUNDLE", help='Excluded Bundle (multiple allowed)')
149 parser.add_option('-f', '--feature',
150 action="append", dest='features',
151 metavar="FEATURE", help='Existing Feature (multiple allowed)')
152 parser.add_option('-d', '--apps',
153 action="append", dest='apps',
154 metavar="FEATURE", help='Required App (multiple allowed)')
155
156 parser.add_option("-A", "--write-app", dest="write_app", action="store_true")
157 parser.add_option("-F", "--write-features", dest="write_features", action="store_true")
Brian O'Connorfc7f5fc2016-04-29 17:04:06 -0700158 parser.add_option("-E", "--write-feature", dest="write_feature", action="store_true")
Brian O'Connor1f165982016-04-06 21:36:09 -0700159
160 (options, args) = parser.parse_args()
161
162 values = {}
Brian O'Connore124f3d2016-04-06 23:54:26 -0700163 if options.feature_coords and options.version and options.title:
Brian O'Connorfc7f5fc2016-04-29 17:04:06 -0700164 parts = options.feature_coords.split(':')
165 values['feature_name'] = parts[1] if len(parts) > 1 else parts[0]
Brian O'Connor1f165982016-04-06 21:36:09 -0700166 values['version'] = options.version
167 values['title'] = options.title
168 else:
169 sys.stderr.write('ERROR: Feature Name, Version, and Title are required\n')
170 sys.stderr.flush()
171 sys.exit(1)
172
173 if options.app_name and options.origin and options.category and options.url:
174 values['app_name'] = options.app_name
175 values['origin'] = options.origin
176 values['category'] = options.category
177 values['url'] = options.url
178 elif options.write_app:
179 sys.stderr.write('ERROR: Feature Name, Version, and Title are required\n')
180 sys.stderr.flush()
181 sys.exit(1)
182
183 values['feature_repo_name'] = options.repo_name if options.repo_name \
Brian O'Connore124f3d2016-04-06 23:54:26 -0700184 else options.feature_coords
Brian O'Connor1f165982016-04-06 21:36:09 -0700185
Brian O'Connorfc7f5fc2016-04-29 17:04:06 -0700186 bundles = []
187 if options.included_bundles:
188 bundles += options.included_bundles
189 if options.excluded_bundles:
190 bundles += options.excluded_bundles
191 feature = generateFeature(bundles=bundles,
192 features=options.features,
193 **values)
194
195 if options.write_feature:
196 print feature
197
Brian O'Connor1f165982016-04-06 21:36:09 -0700198 if options.write_features:
Brian O'Connorfc7f5fc2016-04-29 17:04:06 -0700199 print generateFeatureFile(features=[ feature ],
Brian O'Connor1f165982016-04-06 21:36:09 -0700200 **values)
Brian O'Connorfc7f5fc2016-04-29 17:04:06 -0700201
Brian O'Connor1f165982016-04-06 21:36:09 -0700202 if options.write_app:
203 print generateAppFile(artifacts=options.included_bundles,
204 apps=options.apps,
205 **values)