Skip to content

Commit 57bdfaf

Browse files
committed
started coding for resources
1 parent 471ecd1 commit 57bdfaf

File tree

5 files changed

+397
-4
lines changed

5 files changed

+397
-4
lines changed

elmclient/_queryparser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
6767
simpleidentifier : ( NAME | "'" SPACYNAME "'" )
6868
69-
NAME : /[a-zA-Z0-9_]\w*/
69+
NAME : /[a-zA-Z0-9_][a-zA-Z0-9_-]*/
7070
7171
value : URI_REF_ESC
7272
| boolean

elmclient/_rm.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from . import server
2727
from . import utils
2828
from . import _newtypesystem
29+
from . import resource
2930

3031
# used for OSLC Query on types
3132
typeresources = {
@@ -65,7 +66,7 @@ class _RM_PA_changeset( _config._Changeset,_RMProject):
6566
pass
6667

6768
@utils.mixinomatic
68-
class RMProject(_project._Project):
69+
class RMProject(_project._Project, resource.Resources_Mixin ):
6970
# A project
7071
# NOTE there is a derived class RMComponent used for RM components - it doesn't offer any
7172
# functionality, and is a separate class only so it's easier to see whether an instance is a component or the overall project
@@ -1275,7 +1276,7 @@ def deliver_changeset( self ):
12751276
#################################################################################################
12761277

12771278
@utils.mixinomatic
1278-
class RMApp(_app._App, oslcqueryapi._OSLCOperations_Mixin, _typesystem.Type_System_Mixin):
1279+
class RMApp (_app._App, oslcqueryapi._OSLCOperations_Mixin, _typesystem.Type_System_Mixin ):
12791280
domain = 'rm'
12801281
project_class = RMProject
12811282
supports_configs = True
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
##
2+
## © Copyright 2023- IBM Inc. All rights reserved
3+
# SPDX-License-Identifier: MIT
4+
##
5+
6+
# example of updating a core artifact
7+
8+
# provide on the commandline the id of an artifact in the project/component/configuration
9+
# also provide on the commandline a string (surrounded in " if it includes space) and this will be put on the front of the existing text of the artifact
10+
11+
import logging
12+
import os.path
13+
import sys
14+
import time
15+
16+
import lxml.etree as ET
17+
18+
import elmclient.server as elmserver
19+
import elmclient.utils as utils
20+
import elmclient.rdfxml as rdfxml
21+
22+
# setup logging - see levels in utils.py
23+
#loglevel = "INFO,INFO"
24+
loglevel = "TRACE,OFF"
25+
levels = [utils.loglevels.get(l,-1) for l in loglevel.split(",",1)]
26+
if len(levels)<2:
27+
# assert console logging level OFF if not provided
28+
levels.append(None)
29+
if -1 in levels:
30+
raise Exception( f'Logging level {loglevel} not valid - should be comma-separated one or two values from DEBUG, INFO, WARNING, ERROR, CRITICAL, OFF' )
31+
utils.setup_logging( filelevel=levels[0], consolelevel=levels[1] )
32+
33+
logger = logging.getLogger(__name__)
34+
35+
utils.log_commandline( os.path.basename(sys.argv[0]) )
36+
37+
jazzhost = 'https://jazz.ibm.com:9443'
38+
39+
username = 'ibm'
40+
password = 'ibm'
41+
42+
jtscontext = 'jts'
43+
rmcontext = 'rm'
44+
45+
# the project+compontent+config that will be updated
46+
proj = "rm_optin_p1"
47+
comp = proj
48+
conf = f"{comp} Initial Stream"
49+
50+
# caching control
51+
# 0=fully cached (but code below specifies queries aren't cached) - if you need to clear the cache, delet efolder .web_cache
52+
# 1=clear cache initially then continue with cache enabled
53+
# 2=clear cache and disable caching
54+
caching = 0
55+
56+
##################################################################################
57+
if __name__=="__main__":
58+
if len(sys.argv) != 3:
59+
raise Exception( 'You must provide an identifier and a string (surrounded by " if including spaces)' )
60+
61+
# create our "server" which is how we connect to DOORS Next
62+
# first enable the proxy so if a proxy is running it can monitor the communication with server (this is ignored if proxy isn't running)
63+
elmserver.setupproxy(jazzhost,proxyport=8888)
64+
theserver = elmserver.JazzTeamServer(jazzhost, username, password, verifysslcerts=False, jtsappstring=f"jts:{jtscontext}", appstring='rm', cachingcontrol=caching)
65+
66+
# create the RM application interface
67+
dnapp = theserver.find_app( f"rm:{rmcontext}", ok_to_create=True )
68+
69+
# open the project
70+
p = dnapp.find_project(proj)
71+
72+
# find the component
73+
c = p.find_local_component(comp)
74+
comp_u = c.project_uri
75+
print( f"{comp_u=}" )
76+
77+
# select the configuration
78+
config_u = c.get_local_config(conf)
79+
print( f"{config_u=}" )
80+
c.set_local_config(config_u)
81+
82+
# find the artifact - using OSLC Query
83+
84+
# get the query capability base URL for requirements
85+
qcbase = c.get_query_capability_uri("oslc_rm:Requirement")
86+
87+
# query for a title and for format=module
88+
artifacts = c.execute_oslc_query(
89+
qcbase,
90+
whereterms=[['dcterms:identifier','=',f'"{sys.argv[1]}"']],
91+
select=['*'],
92+
prefixes={rdfxml.RDF_DEFAULT_PREFIX["dcterms"]:'dcterms'} # note this is reversed - url to prefix
93+
)
94+
95+
# print( f"{artifacts=}" )
96+
97+
if len(artifacts)==0:
98+
raise Exception( f"No artifact with identifier '{sys.argv[1]}' found in project {proj} component {comp} configuration {conf}" )
99+
elif len(artifacts)>2:
100+
for k,v in artifacts.items():
101+
print( f'{k} ID {v.get("dcterms:identifier","???")} Title {v.get("dcterms:title","")}' )
102+
raise Exception( "More than one artifcact with that id in project {proj} component {comp} configuraition {conf}" )
103+
104+
# find the core artifact - it has a value for rm_nav:parent
105+
theartifact_u = None
106+
for artifact in artifacts.keys():
107+
# print( f"Testing parent on {artifact=}" )
108+
if artifacts[artifact].get("rm_nav:parent") is not None:
109+
theartifact_u = artifact
110+
break
111+
112+
if not theartifact_u:
113+
raise Exception( "Artifact with rm_nav:parent not found!" )
114+
115+
print( f"Found core artifact {theartifact_u=}" )
116+
117+
art = c.loadResource( theartifact_u )
118+
119+
print( f"{art=}" )
120+
print( vars( art ) )
121+
122+
burp
123+
# now get the artifact content and its etag
124+
theartifact_x, etag = c.execute_get_rdf_xml( theartifact_u, return_etag=True, intent="Retrieve the artifact" )
125+
print( f"{ET.tostring(theartifact_x)=}\n" )
126+
127+
# update the text - this is always xhtml in a div below jazz_rm:primaryText
128+
# NOTE the xml primary text div is a tag hierarchy so setting the text below it just updates the top-level tag, i.e. doesn't remove
129+
# any subtags - if you want to replace the entire context then you need to remove those other tags!
130+
thetext = rdfxml.xml_find_element( theartifact_x, ".//jazz_rm:primaryText/xhtml:div" )
131+
thetext.text = sys.argv[2] + thetext.text
132+
133+
# PUT it back to update the artifact
134+
response = c.execute_post_rdf_xml( theartifact_u, data=theartifact_x, put=True, cacheable=False, headers={'If-Match':etag}, intent="Update the artifact" )
135+
print( f"{response.status_code}" )
136+
location = response.headers.get('Location')
137+
if response.status_code != 200:
138+
raise Exception( "PUT failed!" )
139+
140+
# get the content again
141+
theartifact_x, etag = c.execute_get_rdf_xml( theartifact_u, return_etag=True, intent="Retrieve the artifact" )
142+
thetext = rdfxml.xml_find_element( theartifact_x, ".//jazz_rm:primaryText/xhtml:div" )
143+
print( f"{ET.tostring(thetext)=}" )
144+

elmclient/rdfxml.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@
6868
'xhtml': 'http://www.w3.org/1999/xhtml',
6969
'xml': 'http://www.w3.org/XML/1998/namespace',
7070
'xsd': 'http://www.w3.org/2001/XMLSchema#',
71-
'xs': 'http://www.w3.org/2001/XMLSchema'
71+
'xs': 'http://www.w3.org/2001/XMLSchema',
72+
'rt': 'https://jazz.ibm.com:9443/rm/types'
7273
}
7374

7475
# Register prefixes to XML system

0 commit comments

Comments
 (0)