in src/sfctl/custom_app.py [0:0]
def _check_folder_structure_and_get_dirs(app_dir):
"""
Check if the given path is a folder. If not, raise an exception indicating only
SF app package folders can be compressed.
Check if the folder given corresponds to a valid application structure. If the package
is valid, return a list of dirs (abs path, normalized using the
_normalize_path function) to be compressed.
If the folder is already compressed, then return empty list.
Example format:
WordCountApp (this is the last segment of the app_dir path)
o WordCountServicePkg
Code
• WordCount.Service.exe
• Other Files
Config
• Settings.xml
ServiceManifest.xml
o WordCountWebServicePkg
Code
• WordCount.WebService.exe
• Other Files
Config
• Settings.xml
ServiceManifest.xml
o ApplicationManifest.xml
The Code and Config folders should be compressed. These will be listed in the Application and Service manifests.
:param app_dir: (str) An absolute path to an application package
:return: A list of strings representing the absolute paths to directories which should
be compressed. Return a CLIError if the provided path is not a dir
"""
# Future optimization: don't copy already compressed packages. Just let the user know
# and upload. This should be an uncommon case, and isn't worth the effort now
to_compress = []
if not os.path.isdir(app_dir):
raise CLIError('Only Service Fabric application packages may be compressed. '
'The following path is not a directory: ' + app_dir)
path_to_app_manifest = os.path.join(app_dir, 'ApplicationManifest.xml')
# An application manifest file should exist directly under the directory passed in
if not os.path.isfile(path_to_app_manifest): # Casing does not matter
raise CLIError('Application package to be compressed is missing ApplicationManifest.xml')
# A list of the service packages. This should be the absolute path
service_packages = []
# Parse the application manifest to find which folders should have the service manifest.
app_manifest_parsed = ET.parse(path_to_app_manifest).getroot()
for child in app_manifest_parsed:
# Use ends with, because the tags start with the xmlns
if child.tag.endswith('ServiceManifestImport'):
# We expect a child element that looks like:
# <ServiceManifestRef ServiceManifestName="CalculatorServicePackage" ServiceManifestVersion="1.0"/>
for inner_child in child:
if inner_child.tag.endswith('ServiceManifestRef'):
path_to_service_package = os.path.join(app_dir, inner_child.attrib.get('ServiceManifestName'))
service_packages.append(path_to_service_package)
# Go through each service package folder and search for the service manifest
# The service manifest defines which packages are the code, config, and data packages, which
# needs to be compressed.
for service_package_path in service_packages:
path_to_service_manifest = os.path.join(service_package_path, 'ServiceManifest.xml')
# Raise exception is the expected service manifest file doesn't exist AND
# if the service package isn't already zipped
if not os.path.isfile(path_to_service_manifest) \
and not os.path.isfile(path_to_service_manifest+'.sfpkg'): # Casing does not matter
raise CLIError('Service package to be compressed is missing ServiceManifest.xml in ' + service_package_path)
service_manifest_parsed = ET.parse(path_to_service_manifest).getroot()
for child in service_manifest_parsed:
if child.tag.endswith('CodePackage') or \
child.tag.endswith('ConfigPackage') or child.tag.endswith('DataPackage'):
# If the app package already compressed,
# then mark a bool somewhere that says that this package is already
# compressed, and expect that we just upload the entire package without copying to any location
# In this case, we would not copy to output dir, and just upload. For partially compressed,
# we should compress just those and throw the compressed in the output folder
# For the case where there is no copy needed, we should print a statement letting the user know.
folder_name = child.attrib.get("Name")
folder_to_compress = os.path.join(service_package_path, folder_name)
if not os.path.isdir(folder_to_compress): # Casing does not matter
raise CLIError(str.format("{0} defined in {1} does not exist",
folder_to_compress, path_to_service_manifest))
to_compress.append(_normalize_path(folder_to_compress))
return to_compress