Skip to content

Instantly share code, notes, and snippets.

@luzpaz
Last active January 13, 2020 10:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save luzpaz/f3bfaaef8aaec9c66b96e0941f6ed7a5 to your computer and use it in GitHub Desktop.
Save luzpaz/f3bfaaef8aaec9c66b96e0941f6ed7a5 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
# FreeCAD Headless AddonManager test
# (c) 2019 FreeCAD community LGPL
"""
The module can be executed with:
./FreeCAD.AppImage -c <path_to_file> AddonManagerHeadless.py
Note:
In order to test updates, it possible to use git reset --hard HEAD~1
which will rollback a repo 1 commit behind master.
"""
import os, re, shutil, stat, sys, tempfile
import pdb # python debugger
import git, readline
import FreeCAD
import addonmanager_utilities as utils
# Blacklisted addons
MACROS_BLACKLIST = ["BOLTS",
"WorkFeatures",
"how to install",
"PartsLibrary",
"FCGear"]
# These addons will print an additional message informing the user
OBSOLETE = ["assembly2",
"drawing_dimensioning",
"cura_engine"]
NOGIT = False # for debugging purposes, set this to True to always use http downloads
def ListRepo():
u = utils.urlopen("https://github.com/FreeCAD/FreeCAD-addons")
if not u:
print("Unable to open URL")
quit()
p = u.read()
if sys.version_info.major >= 3 and isinstance(p, bytes):
p = p.decode("utf-8")
u.close()
p = p.replace("\n"," ")
p = re.findall("octicon-file-submodule(.*?)message",p)
basedir = FreeCAD.getUserAppDataDir()
moddir = basedir + os.sep + "Mod"
repos = []
# querying official addons
for l in p:
#name = re.findall("data-skip-pjax=\"true\">(.*?)<",l)[0]
res = re.findall("title=\"(.*?) @",l)
if res:
name = res[0]
else:
print("AddonMananger: Debug: couldn't find title in",l)
continue
# Print repo name by itself
# print(name)
#url = re.findall("title=\"(.*?) @",l)[0]
url = utils.getRepoUrl(l)
if url:
addondir = moddir + os.sep + name
#print ("found:",name," at ",url)
if os.path.exists(addondir) and os.listdir(addondir):
# make sure the folder exists and it contains files!
state = 1
else:
state = 0
repos.append([name,url,state])
# querying custom addons
# customaddons = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons").GetString("CustomRepositories","").split("\n")
# for url in customaddons:
# if url:
# name = url.split("/")[-1]
# if name.lower().endswith(".git"):
# name = name[:-4]
# addondir = moddir + os.sep + name
# if not os.path.exists(addondir):
# sfor repo in repos:tate = 0
# else:
# state = 1
# repos.append([name,url,state])
if not repos:
print("Unable to download addon list.")
else:
repos = sorted(repos, key=lambda s: s[0].lower())
print("List official available Addons:\n")
for repo in repos:
# addon installed
if repo[2] == 1:
# distinguish w/ preceding '+'
print(' +\t' + repo[0])
# addom not installed
if repo[2] == 0:
# distinguish w/ preceding 'x'
print('x\t' + repo[0])
# print a legend
print('\nLegend:\n+ = Installed\nx = Not Installed\n')
# just show what addons are installed
print('Currently installed Addons:')
for repo in repos:
if repo[2] == 1:
print('\t'+repo[0])
return(repos)
def CheckUpdateRepo(repos):
basedir = FreeCAD.getUserAppDataDir()
moddir = basedir + os.sep + "Mod"
# upds = [] # store updates
for repo in repos:
if repo[2] == 1:
print("Checking updates for",repo[0])
clonedir = moddir + os.sep + repo[0]
# if os.path.exists(clonedir):
# # check if this addon was not installed with git
# if not os.path.exists(clonedir + os.sep + '.git'):
# # It wasn't, therefore repair addon installed with raw download
# # creating a git.Repo object to represent repo
# bare_repo = git.Repo.clone_from(repo[1], clonedir + os.sep + '.git', bare=True)
# try:
# with bare_repo.config_writer() as cw:
# cw.set('core', 'bare', False)
# except AttributeError:
# if not gitpython_warning:
# print('Outdated GitPython detected, consider upgrading with pip')
# gitpython_warning = True
# cw = bare_repo.config_writer()
# cw.set('core', 'bare', False)
# del cw
# repo = git.Repo(clonedir)
# repo.head.reset('--hard')
# clone the addon repo
gitrepo = git.Git(clonedir)
try:
gitrepo.fetch()
# TODO: (?) write a little regex for "Your branch is up to date"
# print(gitrepo.status()+'\n')
repos[repos.index(repo)][2] = 2 # mark as already installed AND already checked for updates
# pdb.set_trace() # breakpoint
except:
print("AddonManager: Unable to fetch git updates for repo",repo[0])
else:
# pdb.set_trace() # breakpoint
# 'git status' will tell us if we need to 'git pull'
# note: print(gitrepo.status()) for troubleshooting
if "git pull" in gitrepo.status():
print('\t' + repo[0] + ' ' + 'has an update')
status = re.findall(r"Your branch (.*)\,", gitrepo.status())
print('\t' + repo[0] + ' ' + status[0] + '\n')
# upds.append(repo) # not sure this is necessary due to:
repos[repos.index(repo)][2] = 3 # mark as already installed AND already checked for updates
# pdb.set_trace() # breakpoint
return(repos)
def UpdateRepo(repos):
'''installs or updates the selected addons'''
basedir = FreeCAD.getUserAppDataDir()
moddir = basedir + os.sep + "Mod"
if not os.path.exists(moddir):
os.makedirs(moddir)
for repo in repos:
if repo[2] == 3: # installed but has an update pending
clonedir = moddir + os.sep + repo[0]
if os.path.exists(clonedir):
print('Updating ' + repo[0] + ' addon...')
# first check if the addon was originally downloaded as a zip
if not os.path.exists(clonedir + os.sep + '.git'):
# Repair addon installed with raw download
bare_repo = git.Repo.clone_from(repo[1], clonedir + os.sep + '.git', bare=True)
try:
with bare_repo.config_writer() as cw:
cw.set('core', 'bare', False)
except AttributeError:
print("Outdated GitPython detected, consider upgrading with pip.")
cw = bare_repo.config_writer()
cw.set('core', 'bare', False)
del cw
repo = git.Repo(clonedir)
repo.head.reset('--hard')
repo = git.Git(clonedir)
try:
answer = repo.pull()
except:
print("Error updating module ",repo[1]," - Please fix manually")
answer = repo.status()
print(answer)
else:
# Update the submodules for this repository
repo_sms = git.Repo(clonedir)
for submodule in repo_sms.submodules:
submodule.update(init=True, recursive=True)
else:
pass
return(repos)
def CheckUpdate(name):
"""Check for updates for a single addon"""
updateAvailable = ''
# do we have GitPython?
try:
import git
except:
#return
print('No GitPython installed...aborting')
quit()
print("Checking for available updates of the "+name+" addon")
# construct the local addon directory location
addondir = os.path.join(FreeCAD.getUserAppDataDir(),"Mod",name)
if os.path.exists(addondir):
if os.path.exists(addondir + os.sep + '.git'):
# local addon dir exists
gitrepo = git.Git(addondir)
try:
# lets pull any new updates
gitrepo.fetch()
if "git pull" in gitrepo.status():
updateAvailable(True)
return
except:
# can fail for any number of reasons, ex. not being online
pass
updateAvailable(False)
if __name__ == '__main__':
repos = ListRepo()
print('\nCheckUpdateRepo()\n')
# pdb.set_trace() # breakpoint
repos = CheckUpdateRepo(repos)
# pdb.set_trace() # breakpoint
repos = UpdateRepo(repos)
# pdb.set_trace() # breakpoint
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment