-
Notifications
You must be signed in to change notification settings - Fork 84
/
Copy pathPopulatePackages.py
executable file
·154 lines (140 loc) · 5.21 KB
/
PopulatePackages.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/usr/bin/env python
# Populate package directories.
#
# python PopulatePackages.py < packages.csv
#
# The input packages.csv table must have these columns:
#
# Package Name,Directory Name,Prefixes,File Numbers,File Names,Globals
#
# Rows with an empty package name specify additional prefixes and
# globals for the most recently named package. Prepend '!' to exclude
# a prefix.
#
#---------------------------------------------------------------------------
# Copyright 2011-2019 The Open Source Electronic Health Record Alliance
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#---------------------------------------------------------------------------
from functools import cmp_to_key
from builtins import object
import sys
import os
import csv
import glob
class Package(object):
def __init__(self, name, path):
self.name = name
self.path = path.strip().replace('/',os.path.sep)
self.included = set()
self.excluded = set()
self.globals = set()
def add_namespace(self, ns):
if ns:
if ns[0] in ('-','!'):
self.excluded.add(ns[1:])
else:
self.included.add(ns)
def add_number(self, n):
if n:
if n[0] == '.':
n = '0' + n
self.globals.add(n) # numbers work just like globals
def add_global(self, g):
if g:
self.globals.add(g)
def order_long_to_short(l,r):
if len(l) > len(r):
return -1
elif len(l) < len(r):
return +1
else:
# cmp replaced: https://stackoverflow.com/questions/22490366/how-to-use-cmp-in-python-3
return (l > r) - (l < r)
def place(src,dst):
sys.stdout.write('%s => %s\n' % (src,dst))
d = os.path.dirname(dst)
if d:
try: os.makedirs(d)
except OSError: pass
os.rename(src,dst)
def populatePackageMapByCSV(input):
packages_csv = csv.DictReader(input)
# Parse packages and namespaces from CSV table on stdin.
packages = []
pkg = None
for fields in packages_csv:
if fields['Package Name']:
pkg = Package(fields['Package Name'], fields['Directory Name'])
packages.append(pkg)
if pkg:
pkg.add_namespace(fields['Prefixes'])
pkg.add_number(fields['File Numbers'])
pkg.add_global(fields['Globals'])
# Construct "namespace => path" map.
namespaces = {}
for p in packages:
for ns in p.included:
namespaces[ns] = p.path
for ns in p.excluded:
if ns not in namespaces:
namespaces[ns] = None
return (packages, namespaces)
#-----------------------------------------------------------------------------
def populate(input):
packages, namespaces = populatePackageMapByCSV(input)
#-----------------------------------------------------------------------------
# Collect routines and globals in current directory.
routines = set(glob.glob('*.m'))
globals = set(glob.glob('*.zwr'))
#-----------------------------------------------------------------------------
# Map by package namespace (prefix).
for ns in sorted(list(namespaces.keys()),key=cmp_to_key(order_long_to_short)):
path = namespaces[ns]
gbls=[]
for gbl in globals:
gblout = gbl.split('+')
'''
Account for "non-explicitly listed" globals which have to been split.
Only check the name of the global for placement by namespace if the number
of the global is found to be 0
'''
gblName = gblout[1] if (len(gblout) > 1 and gblout[0].split('-')[0]=="0") else gblout[0]
if gblName.startswith(ns):
gbls.append(gbl)
rtns = [rtn for rtn in routines if rtn.startswith(ns)]
if (rtns or gbls) and not path:
sys.stderr.write('Namespace "%s" has no path!\n' % ns)
continue
routines.difference_update(rtns)
globals.difference_update(gbls)
for src in sorted(rtns):
place(src,os.path.join(path,'Routines',src))
for src in sorted(gbls):
place(src,os.path.join(path,'Globals',src))
# Map globals explicitly listed in each package.
for p in packages:
gbls = [gbl for gbl in globals
if gbl[:-4].split('+')[0].split('-')[0] in p.globals]
globals.difference_update(gbls)
for src in sorted(gbls):
place(src,os.path.join(p.path,'Globals',src))
# Put leftover routines and globals in Uncategorized package.
for src in routines:
place(src,os.path.join('Uncategorized','Routines',src))
for src in globals:
place(src,os.path.join('Uncategorized','Globals',src))
def main():
populate(sys.stdin)
if __name__ == '__main__':
main()