Skip to content

Commit b6e1fae

Browse files
committed
adding function for difference tree
1 parent 9abb0fc commit b6e1fae

File tree

5 files changed

+120
-38
lines changed

5 files changed

+120
-38
lines changed

README.md

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ After installation, you should be able to run `shub` on the command line, withou
3030
Please specify one or more containers with --image(s)
3131

3232

33-
$ shub --help
33+
$ shub --help
3434
usage: shub [-h] [--image IMAGE] [--images IMAGES] [--debug]
3535
[--outfolder OUTFOLDER] [--package] [--tree] [--simtree]
36-
[--simcalc] [--size SIZE]
36+
[--subtract] [--simcalc] [--size SIZE]
3737

3838
Singularity Hub command line tool
3939

@@ -49,6 +49,8 @@ After installation, you should be able to run `shub` on the command line, withou
4949
--package package a singularity container for singularity hub
5050
--tree view the guts of an singularity image (use --image)
5151
--simtree view common guts between two images (use --images)
52+
--subtract subtract one container image from the second to make
53+
a difference tree (use --images first,subtract)
5254
--simcalc calculate similarity (number) between images based on
5355
file contents.
5456
--size SIZE If using Docker or shub image, you can change size
@@ -114,10 +116,12 @@ This will open up something that looks like this:
114116
An [interactive demo](https://singularityware.github.io/singularity-python/examples/container_tree) is also available, and see the [example](examples/container_tree) for updates.
115117

116118

117-
### Compare Containers
119+
### Visualize Containers
118120

119121
#### Container Similarity Tree
120122

123+
![examples/similar_tree/simtree.png](examples/similar_tree/simtree.png)
124+
121125
What do two containers have in common, in terms of files and folders? shub provides a command line function for rendering a view to (immediately) show the similarity between to container images:
122126

123127

@@ -139,26 +143,52 @@ Or two Docker images:
139143
If you need output for any of the following, you can add the `--debug` argument. Note that when generating docker comparisons, the back end is obtaining the layers, creating the images, importing and packaging, so the result is not instantanous.
140144

141145

146+
An [interactive demo](https://singularityware.github.io/singularity-python/examples/similar_tree/) is also available.
147+
148+
149+
#### Container Difference Tree
150+
What files and folders differ between two containers? What does it look like if I subtract one image from the second? `shub` provides a command line tool to generate a visualization to do exactly this.
151+
152+
153+
shub --subtract --images docker://ubuntu:latest.docker://centos:latest
154+
155+
As with `simtree`, this function supports both docker and singularity images as inputs.
156+
157+
![examples/difference_tree/difftree.png](examples/difference_tree/difftree.png)
158+
159+
An [interactive demo](https://singularityware.github.io/singularity-python/examples/difference_tree/) is also available.
160+
161+
162+
### Compare Containers
163+
The same functions above can be used to show the exact similarities (intersect) and differences (files and/or folders unique to two images) between two images. You can get a data structure with this information as follows:
164+
165+
166+
from shub.views import compare_containers
167+
168+
image1 = 'ubuntu.img'
169+
image2 = 'centos.img'
170+
by = "files.txt" # can also be "folders.txt", or a list with both
171+
172+
comparison = compare_containers(image1,image2,by=by)
173+
174+
142175

143176
#### Calculate similarity of images
144177

145178
We can calculate similarity of images based on the file content inside. For an example, see [examples/calculate_similarity](examples/calculate_similarity). We can compare two local images as follows:
146179

147180
$ shub --images /home/vanessa/Desktop/ubuntu.img,/home/vanessa/Desktop/ubuntu.img --simcalc
148181
149-
and the same applies for specification of Docker images, as in the previous example. Note that we are specifying `images` for the argument instead of `image`, and it's a single string of image names separated by a comma. For this argument you can specify an image or package.
182+
and the same applies for specification of Docker images, as in the previous example. Note that we are specifying `images` for the argument instead of `image`, and it's a single string of image names separated by a comma.
150183

151-
![examples/similar_tree/simtree.png](examples/similar_tree/simtree.png)
152-
153-
An [interactive demo](https://singularityware.github.io/singularity-python/examples/similar_tree/) is also available.
154184

155185

156186
### Build your container
157187
More information coming soon.
158188

159189

160190
### Functions Provided
161-
You can also use the library as a module, and import singularity-python functions into your application.
191+
You can also use the library as a module, and import singularity-python functions into your application. If you would like to see specific examples for something, [please ask](https://github.com/singularityware/singularity-python)!
162192

163193

164194
## Help and Contribution

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
name="singularity",
88

99
# Version number:
10-
version="0.34",
10+
version="0.36",
1111

1212
# Application author details:
1313
author="Vanessa Sochat",

singularity/app.py

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from singularity.views import (
22
container_tree,
3-
container_similarity
3+
container_similarity,
4+
container_difference
45
)
56

67
from flask import (
@@ -51,30 +52,37 @@ def app_container_tree():
5152
files=app.viz['files'],
5253
container_name=container_name)
5354

54-
#@app.route('/container/difftree')
55-
#def difference_tree():
56-
# # The server will store the package name and result object for query
57-
# if app.viz == None:
58-
# app.viz = diff_tree(app.packages[0],app.packages[1])
59-
# container1_name = os.path.basename(app.packages[0]).split(".")[0]
60-
# container2_name = os.path.basename(app.packages[1]).split(".")[0]
61-
# title = "%s minus %s" %(container1_name,container2_name)
62-
# return render_template('container_tree.html',graph=app.viz['graph'],
63-
# files=app.viz['files'],
64-
# container_name=title)
55+
@app.route('/containers/subtract')
56+
def difference_tree():
57+
# The server will store the package name and result object for query
58+
if app.viz == None:
59+
app.viz = container_difference(app.images[0],app.images[1])
60+
container1_name,container2_name = get_container_names()
61+
title = "%s minus %s" %(container1_name,container2_name)
62+
return render_template('container_tree.html',graph=app.viz['graph'],
63+
files=app.viz['files'],
64+
container_name=title)
6565

6666
@app.route('/containers/similarity')
6767
def app_similar_tree():
6868
# The server will store the package name and result object for query
6969
if app.viz == None:
7070
app.viz = container_similarity(app.images[0],app.images[1])
71-
container1_name = os.path.basename(app.images[0]).split(".")[0]
72-
container2_name = os.path.basename(app.images[1]).split(".")[0]
71+
container1_name,container2_name = get_container_names()
7372
title = "%s INTERSECT %s" %(container1_name,container2_name)
7473
return render_template('container_tree.html',graph=app.viz['graph'],
7574
files=app.viz['files'],
7675
container_name=title)
7776

77+
def get_container_names():
78+
'''return container names for one or more images, depending on what
79+
app initialized for.
80+
'''
81+
if app.images != None:
82+
container1_name = os.path.basename(app.images[0]).split(".")[0]
83+
container2_name = os.path.basename(app.images[1]).split(".")[0]
84+
return container1_name,container2_name
85+
return None
7886

7987
# START FUNCTIONS ##################################################
8088

@@ -97,6 +105,16 @@ def make_sim_tree(image1,image2,port=None):
97105
webbrowser.open("http://localhost:%s/containers/similarity" %(port))
98106
app.run(host="0.0.0.0",debug=False,port=port)
99107

108+
# Function to make difference tree for two images
109+
def make_diff_tree(image1,image2,port=None):
110+
app.images = [image1,image2]
111+
if port==None:
112+
port=8088
113+
print("Pandas... just let them go.")
114+
webbrowser.open("http://localhost:%s/containers/subtract" %(port))
115+
app.run(host="0.0.0.0",debug=True,port=port)
116+
117+
100118
if __name__ == '__main__':
101119
app.debug = False
102120
app.run(host='0.0.0.0')

singularity/scripts.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ def get_parser():
5050
help="view common guts between two images (use --images)",
5151
default=False, action='store_true')
5252

53+
# Compare two images (a similarity tree)
54+
parser.add_argument('--subtract', dest='subtract',
55+
help="subtract one container image from the second to make a difference tree (use --images first,subtract)",
56+
default=False, action='store_true')
57+
5358
# Compare two images (get numerical comparison)
5459
parser.add_argument('--simcalc', dest='simcalc',
5560
help="calculate similarity (number) between images based on file contents.",
@@ -110,6 +115,7 @@ def main():
110115
make_tree(image)
111116
clean_up(image,existed)
112117

118+
113119
# The user wants to package the image
114120
elif args.package == True:
115121
from singularity.package import package
@@ -138,11 +144,17 @@ def main():
138144
bot.logger.error("Cannot find image. Exiting.")
139145
sys.exit(1)
140146

141-
# the user wants to make a tree
147+
# the user wants to make a similarity tree
142148
if args.simtree == True:
143149
from singularity.app import make_sim_tree
144150
make_sim_tree(image1,image2)
145151

152+
# the user wants to make a difference tree
153+
if args.subtract == True:
154+
from singularity.app import make_diff_tree
155+
make_diff_tree(image1,image2)
156+
157+
146158
if args.simcalc == True:
147159
from singularity.views import calculate_similarity
148160
score = calculate_similarity(image1,image2,by="files.txt")

singularity/views.py

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
# COMPARISON FUNCTIONS ############################################################
2626
###################################################################################
2727

28-
def compare_containers(container1,container2,by="files.txt"):
28+
def compare_containers(container1,container2,by=None):
2929
'''compare_containers will generate a data structure with common and unique files to
3030
two images. If environmental variable SINGULARITY_HUB is set, will use container
3131
database objects.
@@ -35,6 +35,8 @@ def compare_containers(container1,container2,by="files.txt"):
3535
:param by: what to compare, one or more of 'files.txt' or 'folders.txt'
3636
default compares just files
3737
'''
38+
if by == None:
39+
by = ["files.txt"]
3840
if not isinstance(by,list):
3941
by = [by]
4042

@@ -65,19 +67,6 @@ def compare_containers(container1,container2,by="files.txt"):
6567
return comparisons
6668

6769

68-
def container_similarity(container1,container2):
69-
'''container_sim will return a data structure to render an html tree (graph) of the intersection (commonalities) between two images or packages
70-
:param container1: the first container object
71-
:param container2: the second container object
72-
'''
73-
comparison = compare_containers(container1,container2,
74-
by=['files.txt','folders.txt'])
75-
files = comparison["files.txt"]['intersect']
76-
folders = comparison['folders.txt']['intersect']
77-
tree = make_container_tree(folders=folders,
78-
files=files)
79-
return tree
80-
8170

8271
def calculate_similarity(container1,container2,by="files.txt"):
8372
'''calculate_similarity will calculate similarity of two containers by files content, default will calculate
@@ -155,6 +144,39 @@ def get_container_contents(container,gets=None,split_delim=None):
155144
# COMPARISON TREES
156145
###################################################################################
157146

147+
148+
def container_difference(container,container_subtract):
149+
'''container_difference will return a data structure to render an html
150+
tree (graph) of the differences between two images or packages. The second
151+
container is subtracted from the first
152+
:param container: the primary container object (to subtract from)
153+
:param container_subtract: the second container object to remove
154+
'''
155+
comparison = compare_containers(container,container_subtract,
156+
by=['files.txt','folders.txt'])
157+
files = comparison["files.txt"]['unique1']
158+
folders = comparison['folders.txt']['unique1']
159+
tree = make_container_tree(folders=folders,
160+
files=files)
161+
return tree
162+
163+
164+
165+
def container_similarity(container1,container2):
166+
'''container_sim will return a data structure to render an html tree
167+
(graph) of the intersection (commonalities) between two images or packages
168+
:param container1: the first container object
169+
:param container2: the second container object
170+
'''
171+
comparison = compare_containers(container1,container2,
172+
by=['files.txt','folders.txt'])
173+
files = comparison["files.txt"]['intersect']
174+
folders = comparison['folders.txt']['intersect']
175+
tree = make_container_tree(folders=folders,
176+
files=files)
177+
return tree
178+
179+
158180
def container_tree(container):
159181
'''tree will render an html tree (graph) of a container
160182
'''

0 commit comments

Comments
 (0)