Last active
January 13, 2020 10:07
-
-
Save luzpaz/f3bfaaef8aaec9c66b96e0941f6ed7a5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- 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