391 lines
14 KiB
Python
391 lines
14 KiB
Python
|
import os
|
||
|
import glob
|
||
|
import json
|
||
|
import re
|
||
|
import subprocess
|
||
|
from subprocess import call, check_output
|
||
|
|
||
|
BOARD = "BluePill_F103C8"
|
||
|
|
||
|
DIR_CORES = "../../STM32"
|
||
|
DIR_PROJECTS = "sources/arduino_projects"
|
||
|
|
||
|
def find_examples(dir, list):
|
||
|
if not os.path.isdir(dir):
|
||
|
return
|
||
|
|
||
|
subdirs = os.listdir(dir)
|
||
|
for subdir in subdirs:
|
||
|
if os.path.exists(dir + '/' + subdir + '/' + subdir + '.ino'):
|
||
|
list.append(dir + '/' + subdir)
|
||
|
|
||
|
if os.path.exists(dir + '/' + subdir + '/' + subdir + '.pde'):
|
||
|
list.append(dir + '/' + subdir)
|
||
|
|
||
|
find_examples(dir + '/' + subdir, list)
|
||
|
|
||
|
def find_directories():
|
||
|
dirs = []
|
||
|
|
||
|
DIR_LIBRARIES = DIR_CORES + "/libraries"
|
||
|
core_libs = os.listdir(DIR_LIBRARIES)
|
||
|
for core_lib in core_libs:
|
||
|
if os.path.exists(DIR_LIBRARIES + "/" + core_lib + '/src'):
|
||
|
dirs.append(DIR_LIBRARIES + "/" + core_lib + '/src')
|
||
|
else:
|
||
|
dirs.append(DIR_LIBRARIES + "/" + core_lib)
|
||
|
|
||
|
find_examples(DIR_LIBRARIES + '/' + core_lib + '/examples', dirs)
|
||
|
|
||
|
return dirs
|
||
|
|
||
|
projects = os.listdir(DIR_PROJECTS)
|
||
|
for project in projects:
|
||
|
if os.path.exists(DIR_PROJECTS + '/' + project + '/src'):
|
||
|
dirs.append(DIR_PROJECTS + '/' + project + '/src')
|
||
|
else:
|
||
|
dirs.append(DIR_PROJECTS + '/' + project)
|
||
|
|
||
|
if os.path.exists(DIR_PROJECTS + '/' + project + '/examples'):
|
||
|
examples = os.listdir(DIR_PROJECTS + '/' + project + '/examples')
|
||
|
|
||
|
#TODO use glob.glob()
|
||
|
for example in examples:
|
||
|
if not os.path.isdir(DIR_PROJECTS + '/' + project + '/examples/' + example):
|
||
|
continue
|
||
|
if os.path.exists(DIR_PROJECTS + '/' + project + '/examples/' + example + '/' + example + '.ino'):
|
||
|
dirs.append(DIR_PROJECTS + '/' + project + '/examples/' + example)
|
||
|
|
||
|
if os.path.exists(DIR_PROJECTS + '/' + project + '/examples/' + example + '/' + example + '.pde'):
|
||
|
dirs.append(DIR_PROJECTS + '/' + project + '/examples/' + example)
|
||
|
|
||
|
subexamples = os.listdir(DIR_PROJECTS + '/' + project + '/examples/' + example)
|
||
|
for subexample in subexamples:
|
||
|
if not os.path.isdir(DIR_PROJECTS + '/' + project + '/examples/' + example + '/' + subexample):
|
||
|
continue
|
||
|
|
||
|
if os.path.isdir(DIR_PROJECTS + '/' + project + '/examples/' + example + '/' + subexample) and os.path.exists(DIR_PROJECTS + '/' + project + '/examples/' + example + '/' + subexample + '/' + subexample + '.ino'):
|
||
|
dirs.append(DIR_PROJECTS + '/' + project + '/examples/' + example + '/' + subexample)
|
||
|
if os.path.isdir(DIR_PROJECTS + '/' + project + '/examples/' + example + '/' + subexample) and os.path.exists(DIR_PROJECTS + '/' + project + '/examples/' + example + '/' + subexample + '/' + subexample + '.pde'):
|
||
|
dirs.append(DIR_PROJECTS + '/' + project + '/examples/' + example + '/' + subexample)
|
||
|
|
||
|
subsubexamples = os.listdir(DIR_PROJECTS + '/' + project + '/examples/' + example + '/' + subexample)
|
||
|
for subsubexample in subsubexamples:
|
||
|
if os.path.isdir(DIR_PROJECTS + '/' + project + '/examples/' + example + '/' + subexample + '/' + subsubexample) and os.path.exists(DIR_PROJECTS + '/' + project + '/examples/' + example + '/' + subexample + '/' + subsubexample + '/' + subsubexample + '.ino'):
|
||
|
dirs.append(DIR_PROJECTS + '/' + project + '/examples/' + example + '/' + subexample + '/' + subsubexample)
|
||
|
if os.path.isdir(DIR_PROJECTS + '/' + project + '/examples/' + example + '/' + subexample + '/' + subsubexample) and os.path.exists(DIR_PROJECTS + '/' + project + '/examples/' + example + '/' + subexample + '/' + subsubexample + '/' + subsubexample + '.pde'):
|
||
|
dirs.append(DIR_PROJECTS + '/' + project + '/examples/' + example + '/' + subexample + '/' + subsubexample)
|
||
|
|
||
|
return dirs
|
||
|
|
||
|
core_includes = os.listdir(DIR_CORES + "/cores/arduino")
|
||
|
|
||
|
|
||
|
def remove_all(lst, key):
|
||
|
return [val for val in lst if val!=key]
|
||
|
|
||
|
def get_includes(filename):
|
||
|
file = open(filename, "r")
|
||
|
includes = []
|
||
|
|
||
|
if "Printoo" in filename: #TODO remove this when SoftwareSerial is available
|
||
|
return includes
|
||
|
|
||
|
declarations = []
|
||
|
|
||
|
for line in file:
|
||
|
if '//' in line:
|
||
|
line = line[:line.index('//')]
|
||
|
|
||
|
line = line.rstrip()
|
||
|
|
||
|
declaration_found = re.search('^([a-zA-Z].* .*\\(.*\\).*){$', line)
|
||
|
if declaration_found:
|
||
|
func_decl = declaration_found.groups()[0] + ';'
|
||
|
if func_decl.startswith('SIGNAL'):
|
||
|
continue
|
||
|
if "::" in func_decl[:func_decl.index('(')]:
|
||
|
continue
|
||
|
if "." in func_decl[:func_decl.index('(')]:
|
||
|
continue
|
||
|
if 'void setup(' in func_decl:
|
||
|
continue
|
||
|
if 'void loop(' in func_decl:
|
||
|
continue
|
||
|
declarations.append(func_decl);
|
||
|
|
||
|
if line.rstrip() == '{':
|
||
|
combined = previous_line.rstrip() + line
|
||
|
declaration_found = re.search('^([a-zA-Z].* .*.*\\(.*\\).*){$', combined)
|
||
|
if declaration_found:
|
||
|
func_decl = declaration_found.groups()[0] + ';'
|
||
|
if 'void setup(' in func_decl:
|
||
|
continue
|
||
|
if 'void loop(' in func_decl:
|
||
|
continue
|
||
|
declarations.append(func_decl);
|
||
|
|
||
|
|
||
|
found = re.search('include.*?"(.*)"', line)
|
||
|
if found:
|
||
|
includes.append(found.groups()[0])
|
||
|
found = re.search('include.*?<(.*)>', line)
|
||
|
if found:
|
||
|
includes.append(found.groups()[0])
|
||
|
|
||
|
|
||
|
previous_line = line
|
||
|
|
||
|
|
||
|
for ignore_include in core_includes:
|
||
|
includes = remove_all(includes, ignore_include)
|
||
|
includes = remove_all(includes, "string.h")
|
||
|
includes = remove_all(includes, "variant.h")
|
||
|
includes = remove_all(includes, "time.h")
|
||
|
|
||
|
if filename.endswith('.ino') or filename.endswith('.pde'):
|
||
|
with open(filename + '.h', 'w') as file:
|
||
|
if declarations:
|
||
|
for include in includes:
|
||
|
if include.startswith('avr/'):
|
||
|
continue
|
||
|
|
||
|
file.write('#include "' + include + '"\n');
|
||
|
file.write("\n".join(declarations))
|
||
|
|
||
|
return includes
|
||
|
|
||
|
dirs = find_directories();
|
||
|
|
||
|
header_to_dir = {}
|
||
|
|
||
|
for dir in dirs:
|
||
|
if 'examples' in dir:
|
||
|
continue
|
||
|
#print dir
|
||
|
headers = [file for file in os.listdir(dir) if file.endswith(('.h', '.hpp'))]
|
||
|
for header in headers:
|
||
|
if header in header_to_dir:
|
||
|
pass
|
||
|
#print header + ": " + header_to_dir[header] + "=>" + dir
|
||
|
else:
|
||
|
header_to_dir[header] = dir
|
||
|
|
||
|
def get_sources(dir, subdir):
|
||
|
sources = [subdir + file for file in os.listdir(dir) if file.endswith(('.h', '.hpp', '.c', '.cpp', '.ino', '.pde'))]
|
||
|
for file in os.listdir(dir):
|
||
|
if os.path.isdir(dir + '/' + file) and file != 'examples':
|
||
|
sources.extend(get_sources(dir + '/' + file, subdir + file + '/'))
|
||
|
return sources
|
||
|
|
||
|
def create_includes():
|
||
|
#print check_output(["find", ".", "-name", "'build-include-*.txt'", "-delete"], stderr=subprocess.STDOUT)
|
||
|
|
||
|
for dir in dirs:
|
||
|
|
||
|
sources = get_sources(dir, '')
|
||
|
|
||
|
dirs_to_include = []
|
||
|
|
||
|
for source in sources:
|
||
|
includes = get_includes(dir + '/' + source)
|
||
|
|
||
|
for include in includes:
|
||
|
skip = False
|
||
|
for s in sources:
|
||
|
if s == include or include.endswith('/' + s) or s.endswith('/' + include):
|
||
|
skip = True
|
||
|
|
||
|
if skip:
|
||
|
continue
|
||
|
|
||
|
if include in header_to_dir:
|
||
|
dirs_to_include.append(header_to_dir[include])
|
||
|
|
||
|
dirs_to_include = list(set(dirs_to_include))
|
||
|
|
||
|
if dir in dirs_to_include:
|
||
|
dirs_to_include.remove(dir)
|
||
|
|
||
|
add = []
|
||
|
|
||
|
for dir_to_include in dirs_to_include:
|
||
|
if os.path.exists(dir_to_include + '/build-include.txt'):
|
||
|
with open(dir_to_include + '/build-include.txt', 'r') as file:
|
||
|
add.extend(file.readline().strip().split(" "))
|
||
|
|
||
|
dirs_to_include.extend(add)
|
||
|
|
||
|
dirs_to_include = list(set(dirs_to_include))
|
||
|
|
||
|
with open(dir + '/build-include.txt', 'w') as file:
|
||
|
for d in dirs_to_include:
|
||
|
file.write(d + ' ')
|
||
|
|
||
|
create_includes()
|
||
|
|
||
|
exit()
|
||
|
|
||
|
already_compiled = []
|
||
|
|
||
|
def make(directory):
|
||
|
if (directory in already_compiled):
|
||
|
return
|
||
|
print directory
|
||
|
|
||
|
already_compiled.append(directory)
|
||
|
|
||
|
#try:
|
||
|
with open(directory + '/build-include-' + ARCH + '.txt') as f:
|
||
|
dependencies= f.readline()
|
||
|
for dependency in dependencies.split():
|
||
|
make(dependency)
|
||
|
#except:
|
||
|
# print 'DEPENDENCIES NOT CREATED'
|
||
|
|
||
|
call(['make', 'clean', 'ARCH='+ARCH, 'BOARD='+BOARD, 'PROJECT='+directory])
|
||
|
|
||
|
try:
|
||
|
os.mkdir(directory+"/build-"+BOARD)
|
||
|
except OSError:
|
||
|
pass
|
||
|
|
||
|
stdout = open(directory+"/build-"+BOARD+"/stdout.txt", "w")
|
||
|
stderr = open(directory+"/build-"+BOARD+"/stderr.txt", "w")
|
||
|
call(['make', 'ARCH='+ARCH, 'BOARD='+BOARD, 'PROJECT='+directory], stdout = stdout, stderr = stderr)
|
||
|
stdout.close()
|
||
|
stderr.close()
|
||
|
|
||
|
#create_includes()
|
||
|
|
||
|
#raise X
|
||
|
|
||
|
for dir in dirs:
|
||
|
make(dir)
|
||
|
#make('sources/arduino_projects/Adafruit_GFX_Library-1.1.5')
|
||
|
#make('sources/arduino_projects/Adafruit_ILI9341-1.0.1/examples/graphicstest')
|
||
|
#make('sources/arduino_projects/LcdProgressBarDouble-1.0.4/examples/DoubleBarPot')
|
||
|
#make('sources/arduino_projects/RTClib-1.2.0')
|
||
|
#make('sources/arduino_projects/Arduino_GUI-1.6.11/examples/01.Basics/Blink')
|
||
|
#make('sources/arduino_projects/SD-1.0.6/src')
|
||
|
#make('sources/arduino_projects/SD-1.0.6/examples/listfiles')
|
||
|
#make('sources/arduino_projects/Cayenne-1.0.1')
|
||
|
#make('sources/arduino_projects/ArduinoJson-5.6.7')
|
||
|
#make('sources/arduino_projects/ArduinoJson-5.6.7/examples/JsonParserExample')
|
||
|
#make('sources/arduino_projects/EMoRo_2560-2.4.1/src')
|
||
|
#make('sources/arduino_projects/Kalman_Filter_Library-1.0.1/examples/MPU6050')
|
||
|
#make('sources/arduino_projects/SparkFun_Graphic_LCD_Serial_Backpack-1.0.1/examples/SparkFunSerialGraphicLCDDemo')
|
||
|
#make('sources/arduino_projects/DHT_sensor_library-1.2.3')
|
||
|
#make('sources/arduino_projects/DHT_sensor_library-1.2.3/examples/DHTtester')
|
||
|
#make('sources/arduino_projects/Adafruit_GPS_Library-1.0.1/examples/leo_locus_erase')
|
||
|
#make('sources/arduino_projects/DimSwitch-1.0.2/examples/DimSwitchTester-ESP-MQTT')
|
||
|
#make('sources/arduino_projects/MFRC522-1.1.8/examples/RFID-Cloner')
|
||
|
#make('sources/arduino_projects/U8glib-1.19.1/examples/HelloWorld')
|
||
|
#make('sources/arduino_projects/Adafruit_CC3000_Library-1.0.3/examples/HTTPServer')
|
||
|
#make('sources/arduino_projects/Adafruit_Fingerprint_Sensor_Library-1.0.0')
|
||
|
#make('sources/arduino_projects/LiquidCrystal_I2C-1.1.2/examples/HelloWorld')
|
||
|
#make('sources/arduino_projects/AccelStepper')
|
||
|
|
||
|
#raise Error
|
||
|
|
||
|
output = []
|
||
|
|
||
|
errors = {}
|
||
|
|
||
|
for dir in dirs:
|
||
|
#print dir
|
||
|
error = False
|
||
|
if not os.path.exists(dir+"/build-"+BOARD+"/stderr.txt"):
|
||
|
continue
|
||
|
|
||
|
with open(dir+"/build-"+BOARD+"/stderr.txt", "r") as file:
|
||
|
for line in file:
|
||
|
#Find the most relevant error line
|
||
|
if 'warning: changing start of section ' in line:
|
||
|
continue
|
||
|
if 'In function ' in line:
|
||
|
continue
|
||
|
if 'In constructor ' in line:
|
||
|
continue
|
||
|
if 'In member function ' in line:
|
||
|
continue
|
||
|
if 'In file included from ' in line:
|
||
|
continue
|
||
|
if 'from sources/' in line:
|
||
|
continue
|
||
|
if 'from ./sources/' in line:
|
||
|
continue
|
||
|
if 'from <command-line>' in line:
|
||
|
continue
|
||
|
|
||
|
if not error: error = line
|
||
|
|
||
|
#print "ERROR = ", error
|
||
|
if not error:
|
||
|
error = "SUCCESS"
|
||
|
|
||
|
errors[dir] = error.strip()
|
||
|
|
||
|
with open('cache/library_index.json') as file:
|
||
|
data = json.load(file)
|
||
|
|
||
|
libraries = {}
|
||
|
|
||
|
for library in data["libraries"]:
|
||
|
libraries[library["name"]] = library
|
||
|
|
||
|
for name, library in libraries.iteritems():
|
||
|
if "github.com" in library["website"]:
|
||
|
api = library["website"].replace("github.com", "api.github.com/repos")
|
||
|
api = api.replace("https", "http")
|
||
|
if api.endswith(".git"):
|
||
|
api = api[:-4]
|
||
|
download_file = "cache/github_api/" + api[len("http://api.github.com/repos")+1:].replace("/", ":")
|
||
|
|
||
|
if os.path.exists(download_file):
|
||
|
with open(download_file) as file:
|
||
|
data = json.load(file)
|
||
|
libraries[name]["github_api"] = data
|
||
|
libraries[name]["sort"] = data["forks_count"] + data["watchers_count"] + data["stargazers_count"] + data["subscribers_count"]
|
||
|
libraries[name]["sort"] = data["stargazers_count"]
|
||
|
|
||
|
zip_file = os.path.basename(library["url"])
|
||
|
projects_folder = DIR_PROJECTS + "/" + zip_file[:-4]
|
||
|
if projects_folder in errors:
|
||
|
libraries[name]["error"] = errors[projects_folder]
|
||
|
elif (projects_folder + "/src") in errors:
|
||
|
libraries[name]["error"] = errors[projects_folder + "/src"]
|
||
|
else:
|
||
|
libraries[name]["error"] = "NOT FOUND"
|
||
|
|
||
|
libraries[name]['example_errors'] = {}
|
||
|
libraries[name]['projects_folder'] = projects_folder
|
||
|
|
||
|
for error_folder in errors:
|
||
|
if 'examples' in error_folder and error_folder.startswith(projects_folder):
|
||
|
#print projects_folder, error_folder, errors[error_folder]
|
||
|
libraries[name]['example_errors'][error_folder] = errors[error_folder]
|
||
|
|
||
|
#if (libraries[name]['author'] == 'Arduino'):
|
||
|
# libraries[name]["sort"] = 10000
|
||
|
|
||
|
|
||
|
|
||
|
def sort_library(a):
|
||
|
if "sort" in libraries[a]:
|
||
|
return libraries[a]["sort"]
|
||
|
else:
|
||
|
return 0
|
||
|
|
||
|
library_names = sorted(libraries, key=sort_library, reverse=True)
|
||
|
|
||
|
for name in library_names:
|
||
|
if 'sort' in libraries[name]:
|
||
|
pass
|
||
|
#print name, libraries[name]["sort"], libraries[name]["website"], libraries[name]["projects_folder"], libraries[name]["error"], libraries[name]["example_errors"]
|
||
|
|
||
|
with open('result.json', 'w') as file:
|
||
|
file.write(json.dumps({'libraries': libraries, 'library_names': library_names}))
|
||
|
|
||
|
|