Skip to content

Commit

Permalink
Integrated RPM
Browse files Browse the repository at this point in the history
  • Loading branch information
marcantondahmen committed Oct 22, 2020
1 parent e9c58b7 commit ea1529d
Show file tree
Hide file tree
Showing 20 changed files with 385 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""
Check for pyRevit core and extension updates and optionally install them.
"""
from rpm.system.ui import UI
from pyrevit.coreutils.ribbon import ICON_LARGE

__context__ = 'zero-doc'

def __selfinit__(script_cmp, ui_button_cmp, __rvt__):
if UI.checkUpdates():
ui_button_cmp.set_title('Install\nUpdates')
update_icon = script_cmp.get_bundle_file('icon-has-updates.png')
ui_button_cmp.set_icon(update_icon, icon_size=ICON_LARGE)
return True

if __name__ == '__main__':
UI.checkUpdates(True)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
"""
Install all extensions defined for this project. You can define extensions for this project in the "Project Setup".
"""
import revitron
from rpm.system.ui import UI
import os
import rpm
from pyrevit.coreutils import logger
from pyrevit import script


mlogger = logger.get_logger(__name__)

if not revitron.Document().isFamily():

out = script.get_output()
UI.printLogo()
UI.printTitle()
out.print_html('Removing registered extensions')

extManager = rpm.ExtensionsManager()
extManager.removeAll()

out.print_html('Getting project dependencies<br>')
lines = revitron.DocumentConfigStorage().get('rpm.extensions', '').split('\r\n')

for line in lines:

items = line.split('\t')

try:
extType = items[0].strip()
extRepo = items[1].strip()
extName = os.path.basename(extRepo).replace('.git', '')
out.print_html('Installing {}'.format(extName))
extManager.install(extName, extRepo, extType)
except:
try:
mlogger.error('Installing {} failed'.format(extName))
except:
pass

out.print_html('<br>Installation has finished. Reloading ...')
rpm.system.Session.reload()
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
Define extensions to be used with this Revit model. Defined extensions can be installed by using the "Install Extensions" button.
"""
import revitron
import System.Windows
from rpw.ui.forms import FlexForm, TextBox, Button, Label


if not revitron.Document().isFamily():

config = revitron.DocumentConfigStorage().get('rpm.extensions')

components = [
Label('Enter one extension per line like this (note the tab after the extension type):', Width=600),
Label('"ui ⇥ https://repository.git" for UI extensions or\r\n"lib ⇥ https://repository.git" for libraries', Height=50, Width=600),
TextBox('extensions', Text=config, TextWrapping=System.Windows.TextWrapping.Wrap, AcceptsTab=True, AcceptsReturn=True, Multiline=True, Height=200, Width=600),
Button('Save', Width=100, HorizontalAlignment=System.Windows.HorizontalAlignment.Right)
]

form = FlexForm('RPM Extensions', components)
form.show()

if 'extensions' in form.values:
revitron.DocumentConfigStorage().set('rpm.extensions', form.values.get('extensions'))

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions Revitron.tab/RPM.panel/Setup.pulldown/bundle.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
layout:
- ProjectSetup[title:Project Setup]
- InstallExtensions[title:Install Extensions]
Binary file added Revitron.tab/RPM.panel/Setup.pulldown/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions Revitron.tab/RPM.panel/bundle.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
layout:
- Setup[title:Project\nSetup]
- CheckForUpdates[title:Check for\nUpdates]
3 changes: 2 additions & 1 deletion Revitron.tab/bundle.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
layout:
- Revitron[beforeall:]
- Revitron[beforeall:]
- RPM
3 changes: 3 additions & 0 deletions lib/rpm/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from system import *
from config import *
from extensions import *
7 changes: 7 additions & 0 deletions lib/rpm/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import pyrevit
import os

RPM_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
RPM_PYREVIT_DIR = pyrevit.HOME_DIR
RPM_PYREVIT_BIN = pyrevit.BIN_DIR + '\\pyrevit'
RPM_EXTENSIONS_DIR = RPM_PYREVIT_DIR + '\\extensions'
65 changes: 65 additions & 0 deletions lib/rpm/extensions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from rpm import config
from pyrevit import script
from pyrevit.coreutils import logger
from datetime import datetime
import os
import json
import subprocess


mlogger = logger.get_logger(__name__)

class ExtensionsManager:

def __init__(self):
self.json = config.RPM_EXTENSIONS_DIR + '\\rpm.json'

def getInstalled(self):
try:
with open(self.json) as jsonFile:
data = json.load(jsonFile)
except:
data = {'installed': dict()}
return data['installed']

def removeAll(self):
for key, ext in self.getInstalled().iteritems():
try:
subprocess.check_output('rmdir /Q /S {}'.format(ext['path']),
stderr=subprocess.STDOUT,
shell=True,
cwd='C:\\')
mlogger.info('Removed extension {}'.format(key))
except:
mlogger.error('Error removing extension {}'.format(key))
data = {'installed': dict()}
script.dump_json(data, self.json)

def install(self, name, repo, extType):
repo = repo.replace('.git', '') + '.git'
cmd = '{} extend {} {} {} --dest="{}"'.format(config.RPM_PYREVIT_BIN, extType, name, repo, config.RPM_EXTENSIONS_DIR)
types = {'ui': 'extension', 'lib': 'lib'}
path = config.RPM_EXTENSIONS_DIR + '\\' + name + '.' + types.get(extType, 'extension')
try:
if not os.path.isdir(path):
subprocess.check_output(cmd,
stderr=subprocess.STDOUT,
shell=True,
cwd='C:\\')
mlogger.info('Installed extension {}'.format(name))
else:
mlogger.error('{} is not empty!'.format(path))
self.register(name, repo, extType, path)
except:
mlogger.error('Installing {} has failed!'.format(name))

def register(self, name, repo, extType, path):
data = {'installed': self.getInstalled()}
data['installed'][os.path.basename(path)] = {
'name': name,
'type': extType,
'repo': repo,
'path': path,
'date': str(datetime.now())
}
script.dump_json(data, self.json)
3 changes: 3 additions & 0 deletions lib/rpm/system/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from update import *
from ui import *
from session import *
12 changes: 12 additions & 0 deletions lib/rpm/system/session.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from pyrevit.loader.sessionmgr import execute_command


class Session:

@staticmethod
def reload():
# Call pyRevit reload command to reload pyRevit
# The reason to call the command instead of using sessionmgr module
# to realod is that the repo has been just updatedm so all
# modules need to be re-imported again in a clean engine.
execute_command('pyrevitcore-pyrevit-pyrevit-tools-reload')
59 changes: 59 additions & 0 deletions lib/rpm/system/ui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from pyrevit import script
from pyrevit import output
from pyrevit import forms
from rpm import config
from rpm.system.update import Update
from rpm.system.session import Session


class UI:

@staticmethod
def checkUpdates(force = False):

hasUpdates = False
out = script.get_output()
pyRevit = Update.checkPyRevit()
extensions = Update.checkExtensions()

if pyRevit:
install = 'Close open Revit sessions and install pyRevit core update now'
skip = 'Skip update and keep Revit sessions open'
res = forms.alert('A pyRevit core update is ready to be installed.\n'
'Note that all running Revit sessions will be closed automatically when installing the update.',
title = 'pyRevit Update',
options = [install, skip])
if res == install:
Update.pyRevit()
else:
hasUpdates = True

if extensions:
install = 'Install extension updates now'
skip = 'Skip updates'
if force:
res = install
else:
res = forms.alert('There are pyRevit extension updates ready to be installed.',
title = 'pyRevit Extensions Updates',
options = [install, skip])
if res == install:
UI.printLogo()
UI.printTitle()
Update.extensions()
out.print_html('<br><br>Update has finished. Reloading ...<br><br>')
Session.reload()
else:
hasUpdates = True

return hasUpdates

@staticmethod
def printLogo():
out = script.get_output()
out.print_html('<div style="text-align:center; margin: 30px 0"><img src="{}" style="max-width:500px;"></div>'.format(config.RPM_DIR + '/svg/rpm-ui.svg'))

@staticmethod
def printTitle():
out = script.get_output()
out.print_html('<h2>Revitron Package Manager</h2>')
95 changes: 95 additions & 0 deletions lib/rpm/system/update.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import subprocess
import os
import glob
from pyrevit import script
from pyrevit.coreutils import logger
from rpm import config


mlogger = logger.get_logger(__name__)

class Update:

@staticmethod
def check(repo):
mlogger.info('Checking updates for {}'.format(repo))
try:
if not os.path.isdir(repo + '\\.git'):
return False
if not Update.remoteExists(repo):
mlogger.error('Remote of repository "{}" not found!'.format(os.path.basename(repo)))
return False
status = Update.git('fetch origin --dry-run', repo)
if status:
mlogger.info(status)
return True
except:
pass
return False

@staticmethod
def checkExtensions():
status = False
for repo in Update.getExtensionRepos():
if Update.check(repo):
status = True
return status

@staticmethod
def checkPyRevit():
return Update.check(config.RPM_PYREVIT_DIR)

@staticmethod
def git(cmd, repo):
return subprocess.check_output('set GIT_TERMINAL_PROMPT=0 && git -c credential.helper= --git-dir={0}\\.git --work-tree={0} {1}'.format(repo, cmd),
stderr=subprocess.STDOUT,
shell=True,
cwd='C:\\')

@staticmethod
def getExtensionRepos():
repos = []
for git in glob.glob('{}\\*\\.git'.format(config.RPM_EXTENSIONS_DIR)):
repos.append(os.path.dirname(git))
return repos

@staticmethod
def pyRevit():
revit = ''
process = subprocess.Popen(['powershell', 'Get-Process Revit | Select-Object Path'], stdout=subprocess.PIPE)
while True:
line = process.stdout.readline()
if 'Revit' in line:
revit = line
break
if not line:
break
os.system('{}\\updatePyRevit.bat "{}" "{}"'.format(os.path.dirname(__file__), config.RPM_PYREVIT_DIR, revit))

@staticmethod
def extension(repo):
if not Update.remoteExists(repo):
mlogger.error('Remote of repository "{}" not found!'.format(os.path.basename(repo)))
return False
status = Update.git('status --untracked-files=no --porcelain', repo)
if status:
print(status)
mlogger.warning('Skipped update, repository not clean!')
else:
print(Update.git('pull', repo))

@staticmethod
def extensions():
out = script.get_output()
for repo in Update.getExtensionRepos():
out.print_html('<br><b>{}</b> &mdash; updating ...'.format(os.path.basename(repo)))
Update.extension(repo)

@staticmethod
def remoteExists(repo):
url = Update.git('remote get-url --all origin', repo).rstrip()
try:
Update.git('ls-remote {}'.format(url), repo)
return True
except:
return False
15 changes: 15 additions & 0 deletions lib/rpm/system/updatePyRevit.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@echo off

echo %1
echo %2
cd %1

:stillRunning
TASKKILL /IM Revit.exe /F
timeout 3 > NUL
tasklist /FI "IMAGENAME eq Revit.exe" 2>NUL | find /I /N "Revit.exe">NUL
if "%ERRORLEVEL%"=="0" goto :stillRunning

git pull origin

START "" %2
Loading

0 comments on commit ea1529d

Please sign in to comment.