-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathUpdateRevitLinks (NEW).py
More file actions
338 lines (284 loc) · 11.4 KB
/
UpdateRevitLinks (NEW).py
File metadata and controls
338 lines (284 loc) · 11.4 KB
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
#========================================================================#
# _____ __
# \_ \__ _ _ __ \ \ __ _ _ __ ___ ___ ___
# / /\/ _` | '_ \ \ \/ _` | '_ ` _ \ / _ \/ __|
# /\/ /_| (_| | | | | /\_/ / (_| | | | | | | __/\__ \
# \____/ \__,_|_| |_| \___/ \__,_|_| |_| |_|\___||___/
#
# Automation of Revit Link Updating initally written for QQT
#
# The Script looks for Revit Links then looks at the folder they came
# from to see if there is a higher numbered revision and if so then
# it will swap to that revision.
#
# January 2019
#
#========================================================================#
import os
import os.path
import fnmatch
import time, datetime
import subprocess as sp
#------------------------------------------------------------------------#
def GetAllLinks():
"""
Params :
No Input Parameters Works on current ActiveDocument
Returns:
A [List] of all of the RevitLinkType elements that contain
the text string '-RVT-' ensuring that all consultant links
are included but no BVN links.
"""
theLinks = (
FilteredElementCollector(doc)
.OfCategory(BuiltInCategory.OST_RvtLinks)
#Only Link Types, NOT a Nested Link
.Where(lambda link: (RevitLinkType == type(link)) and not(link.IsNestedLink))
)
theLinks = theLinks.Where(lambda link: Element.Name.GetValue(link).Contains('-RVT-'))
return theLinks.ToList()
#------------------------------------------------------------------------#
def GetLinkName(aLink):
"""
Params :
aLink - RevitLinkType
Returns :
Returns the name of the Revit Link file
"""
#return [x.strip() for x in Element.Name.GetValue(aLink).split(':')]
return Element.Name.GetValue(aLink)
#------------------------------------------------------------------------#
def GetLinkFolderPath(aLink):
thePath = ''
#Get the External Reference
er = aLink.GetExternalFileReference()
#Make sure it isn't Null
if not(er):
print GetLinkName(aLink)
else:
#Get the Model Path
mp = er.GetPath()
#Convert the Model Path to a human readable format
#Also convert relative paths to absolute paths
modelpath = ModelPathUtils.ConvertModelPathToUserVisiblePath(mp)
thePath = os.path.dirname(os.path.abspath(modelpath))
return thePath
#------------------------------------------------------------------------#
def GetRevNumberFromFileName(filename):
linkinfo = filename.split('-')
if 'RVT' in linkinfo:
# return the item in the list after 'RVT'
# which should be the revision number.
revnumber = int(linkinfo[linkinfo.IndexOf('RVT')+1])
else:
revnumber = 0
return revnumber
#------------------------------------------------------------------------#
#def isValidFile(fn, filestart):
# return (os.path.isfile(fn) and fn.StartsWith(filestart) and fn.EndsWith('.rvt'))
#------------------------------------------------------------------------#
def GetCandidateRevisions(contents):
for c in contents:
print 'Item: ' + c
if os.path.isfile(c):
print 'file: Yes'
else:
print 'folder: Yes'
if c.EndsWith('.rvt'):
print 'Revit File'
else:
print 'Not Revit File'
#------------------------------------------------------------------------#
def GetLatestRevisionFromFolder(aLink):
#Get the path that the Link comes from
folderpath = GetLinkFolderPath(aLink)
filename = Element.Name.GetValue(aLink)
#Only check if the file is from the Revit Links Folder
if folderpath.Contains('Revit Links'):
#Get the start of the filename up to the Revision
#so that we can filter files we are interested in.
filestart = filename[:filename.find('-RVT-')]
# list of Revit files in the folder that match
# both the start of the filename and end with .rvt
#contents = [fn for fn in os.listdir(folderpath) #<----<< Rewrite Longhand
# if fn.StartsWith(filestart)]
#something like this
filenames = fnmatch.filter(os.listdir(folderpath), filestart + '*.rvt')
#filenames = GetCandidateRevisions(contents)
#for f in filenames: print f
highest = 0
print folderpath
#If more than one file... loop through and find highest revision
for afile in filenames:
num = GetRevNumberFromFileName(afile)
if num > highest:
highest = num
theFile = afile
else:
#We have a match
if num == highest:
theFile = afile
#Return an updated File Path of a higher Revision
return (folderpath,theFile)
else:
#Return an empty string if not from 'Revit Links Folder'.
return ''
#------------------------------------------------------------------------#
def GetLinkedDocuments():
theDocuments = {}
for aDoc in doc.Application.Documents:
theDocuments.update({aDoc.Title: aDoc})
return theDocuments
#------------------------------------------------------------------------#
def GetLinkedDocumentDoc(theDocuments, aLinkName):
#remove the ".rvt"
aLinkName = aLinkName[:aLinkName.find('.rvt')]
#Check that the document is in the open documents (ie a Link)
if theDocuments.ContainsKey(aLinkName):
#---------print 'File: ' + aLinkName + ' is in the Dictionary'
linkdoc = theDocuments[aLinkName]
else:
linkdoc = None
return linkdoc
#------------------------------------------------------------------------#
def GetClosedWorksetIds(linkdoc):
#Get the Worksets
theWorksets = (
FilteredWorksetCollector(linkdoc)
.Where(lambda ws: ws.Kind == WorksetKind.UserWorkset)
)
ClosedWorksets = []
for aWorkset in theWorksets:
if not(aWorkset.IsOpen):
ClosedWorksets.Add(aWorkset.Id)
#Return the list of Ids
return ClosedWorksets
#------------------------------------------------------------------------#
def LogListClosedWorksets(linkdoc, wslist):
wst = linkdoc.GetWorksetTable()
wlist = ''
#Print the list of Closed Worksets to the Log
for w in wslist:
wlist = wlist + '\n [-] ' + wst.GetWorkset(w).Name
return wlist
#------------------------------------------------------------------------#
def CreateLogFile(logtext):
#Establish the Log Filename
theversion = uiapp.Application.VersionNumber
theModelName = doc.Title[:doc.Title.LastIndexOf('_')]
timestamp = datetime.datetime.now().strftime("(%Y-%m-%d - %H-%M-%S)")
thePath = r'X:\003 - Multiplex\Design\BIM\_Revit\8.0 Revit Links\1.0 MPX\000 LOGS' + '\\' + theModelName + '_ReloadLinks_' + timestamp + '.log'
#Open, Write to the File & Close
fp = open(thePath, 'w')
fp.write(logtext)
fp.close()
#Then Open in Notepad.exe
NotepadCommandString = 'notepad.exe'
logfile = thePath
sp.Popen([NotepadCommandString,logfile])
#------------------------------------------------------------------------#
NotWorksharedLinks = []
NotFoundLinkDocs = []
BADModels = []
LogSeparator = '+' + '-'*80 + '+'
#Get All of the current open documents
theDocuments = GetLinkedDocuments()
# Get All of the Links (LinkTypes Only)
theLinks = GetAllLinks()
#Create a Log Element for each link
linklog = ''
linklog = linklog + '\n' + LogSeparator
#For Each of the Links:
for aLink in theLinks:
theLinkPath = GetLinkFolderPath(aLink)
theLinkName = GetLinkName(aLink)
if '8.0 Revit Links' in theLinkPath:
linklog = linklog + '\nLink Name = ' + theLinkName
linklog = linklog + '\nLink Path = ' + theLinkPath
#Check to see if this link is loaded so we can re-instate this status
isloaded = aLink.IsLoaded(doc,aLink.Id)
#If the Link was unloaded, reload it while we check for updates.
#It will be unloaded at the end.
if not isloaded:
aLink.Reload()
#Get the Current Revision of this link
theLinkCurrentRev = GetRevNumberFromFileName(theLinkName)
#Get the Highest Revision Available
newLinkPath, newLinkName = GetLatestRevisionFromFolder(aLink)
newFilePath = newLinkPath + '\\' + newLinkName
#Get the Potential New Revision Number
NewRevision = GetRevNumberFromFileName(newLinkName)
if theLinkCurrentRev.Equals(NewRevision):
#No Relinking is required.
linklog = linklog + '\nFile: ' + theLinkName + ' is already up to date at Rev ' + theLinkCurrentRev.ToString()
else:
#We need to relink from the newer revision.
linklog = linklog + '\nNeed to update from Rev ' + theLinkCurrentRev.ToString() + ' to Rev ' + NewRevision.ToString()
linkdoc = GetLinkedDocumentDoc(theDocuments, theLinkName)
#make Sure we got a valid document back.
if linkdoc:
if linkdoc.IsWorkshared:
#If the link is Workshared we need to make sure we match any closed Worksets
#--------print 'Getting the Workset Status of the link:' + linkdoc.Title
#Get the List of Closed Worksets
closedWS = GetClosedWorksetIds(linkdoc)
wc = WorksetConfiguration()
wc.Close(closedWS)
#worksetinfo(linkdoc)
linklog = linklog + '\nClosed Worksets as follows:'
linklog = linklog + LogListClosedWorksets(linkdoc,closedWS)
#Relink From the New Revision with Workset Control
#print newFilePath
modelpath = ModelPathUtils.ConvertUserVisiblePathToModelPath(newFilePath)
#using the WorksetConfiguration.
#aLink.LoadFrom(modelpath, wc)
#Using null
aLink.LoadFrom(modelpath, None)
#If File was originally unloaded the reset to Unloaded
#if not(isloaded):
# linklog = linklog + '\nResetting the Link to UNLOADED.'
# aLink.Unload(null)
else:
NotWorksharedLinks.Add(GetLinkName(aLink))
linklog = linklog + '\nThis file is NOT Workshared...!'
#Relink From the New Revision (No Workset Control)
modelpath = ModelPathUtils.ConvertUserVisiblePathToModelPath(newFilePath)
try:
aLink.LoadFrom(modelpath, WorksetConfiguration())
except Exception as e:
BADModels.append((GetLinkName(aLink), e.message))
linklog = linklog + "ERROR LOADING MODEL"
linklog = linklog + e.message
print e.message
#If File was originally unloaded the reset to Unloaded
else:
linklog = linklog + '\nlinkDoc Not Found'
NotFoundLinkDocs.Add(GetLinkName(aLink))
linklog = linklog + '\n' + LogSeparator
else:
pass
#print '... not a Revit Link'
#If the Link was unloaded prior to being up-revved - reistate.
#if not isloaded:
# aLink.Unload('Need to figure out how to use this method)
#List any non-Workshared links
if NotWorksharedLinks.Count > 0:
linklog = linklog + '\nThe Following Links are not workshared...!!\n'
for nwl in NotWorksharedLinks:
linklog = linklog + '\n' + nwl
#List any files that weren't found and need manual attention
if NotFoundLinkDocs.Count > 0:
linklog = linklog + '\nThe Following Links were not found.'
linklog = linklog + '\nThese may be Unloaded.'
linklog = linklog + '\nReload and try again'
linklog = linklog + ':'
for l in NotFoundLinkDocs:
linklog = linklog + '\n' + l
if BADModels.Count > 0:
linklog = linklog + '\nThe Following Links could not be loaded.'
for m in BADModels:
linklog = linklog + '\n' + m[0]
linklog = linklog + '\n' + m[1]
#Print the Link Log to the Log File
CreateLogFile(linklog)
print linklog