← Back to team overview

kicad-developers team mailing list archive

Re: [PATCH] Fix handle ZoneConnection enum in python scripting agains BZR6098

 

In response to a message written on 18.08.2015, 16:23, from jp charras:
Le 18/08/2015 08:38, LordBlick a écrit :
Attached, tested(on PLD Linux) patch implements the following changes:
- not finished python scripting issue - brings pad.GetZoneConnection()
and in
example pad.SetZoneConnection(pcbnew.PAD_ZONE_CONN_FULL) to full workable.
- cleanup namespace pretty artistic disorder in enum ZoneConnection in
pcbnew/zones.h to self-explained names unification:
      PAD_ZONE_CONN_INHERITED = -1
      PAD_ZONE_CONN_NONE
      PAD_ZONE_CONN_THERMAL
      PAD_ZONE_CONN_FULL
      PAD_ZONE_CONN_THT_THERMAL
There is no influence for instability after applying.

Committed. Thanks.

Be careful with this kind of changes: it can break existing Python
scripts like wizards.
I understand it. Eventually it might be changed after next stable release, where all stable users can use old namespace, then on production namespace can be cleaned. All scripts included in repository of course will be updated, because changes are generated by search & replace script, not manually. Example diff generator in attachment
(This is not the case for this change)
Of course not, because that functionality there was not working in Python before… ;)
Thanks for commit.
--
Best Regards,
LordBlick
#!/usr/bin/env python2
# -*- encoding: utf-8 -*-
# -*- coding: utf-8 -*-

debug_level = 1

dbg_files = 'zones.h', 'class_zone.cpp'

import re
from os import path as ph, readlink as rlnk, rename as mv, makedirs
from shutil import copy2 as cp

'''
rename_rex_list = (
	(r'\b(PAD_)((CIRCLE)|(OVAL)|(TRAPEZOID)|(RECT))\b', '\\g<1>SHAPE_\\g<2>'),
	(r'\b(PAD_)((STANDARD)|(SMD)|(CONN))\b', '\\g<1>TYPE_\\g<2>'),
	(r'\b(PAD_)HOLE_NOT_PLATED\b', '\\g<1>TYPE_NPTH'),
	)
'''

rename_rex_list = (
	(r'\bUNDEFINED_CONNECTION\b', 'PAD_ZONE_CONN_INHERITED'),
	(r'\bPAD_NOT_IN_ZONE\b', 'PAD_ZONE_CONN_NONE'),
	(r'\bTHERMAL_PAD\b', 'PAD_ZONE_CONN_THERMAL'),
	(r'\bPAD_IN_ZONE\b', 'PAD_ZONE_CONN_FULL'),
	(r'\bTHT_THERMAL\b', 'PAD_ZONE_CONN_THT_THERMAL'),
	)
'\b(UNDEFINED_CONNECTION)|(PAD_NOT_IN_ZONE)|(THERMAL_PAD)|(PAD_IN_ZONE)|(THT_THERMAL)\b'

strict_rex_list = (
	('pcbnew.i', '^(.*include\s*\<)(class_zone\.h)(\>.*)$', '\\g<1>\\g<2>\\g<3>\n\\g<1>zones.h\\g<3>'),
	)

H = ph.expanduser('~') # Home dir
hh = lambda s: s.replace(H, '~')
from sys import stdout as sto
_p = lambda _str: sto.write(hh(str(_str)))
_err  = lambda _str: sto.write(_str)
def _dbg(s, level=1):
	if debug_level>=level:
		_p(s)
unp_dir = "%s/rpm/BUILD/" % H
diff_root_dn = ''
output_fn = unp_dir+'pyZoneConnection'
#ls_fn = []

class Patcher:
	def __init__(it):
		it.search_and_prepare()
		#it.diff()

	def search_and_prepare(it):
		#Search for newest build tree
		from glob import glob as ls
		bld = ('main', 'stable')[0]
		rexBldDirBzrRev = re.compile("kicad-sources-BZR\.(?P<BzrRev>\d+)-"+bld, re.U)
		lsBldDirs = []
		for dirName in ls(unp_dir+'*'):#+'kicad-sources-BZR.*-'+bld
			mBldDirBzrRev = rexBldDirBzrRev.search(dirName)
			if not(mBldDirBzrRev) or(not(ph.isdir(dirName))):
				continue
			bzrRev = int(mBldDirBzrRev.group('BzrRev'))
			lsBldDirs.append( (bzrRev, dirName) )
		if not(lsBldDirs):
			_p("No usable build tree in %sr…\n" % hh(unp_dir))
			return
		global diff_root_dn, output_fn #, ls_fn
		revno, diff_root_dn = tuple(reversed(sorted(lsBldDirs)))[0]
		output_fn += "-BZR%d.path" % revno
		diff_tree = diff_root_dn+'/'
		_p("Freshest usable build tree: '%s'\n" % hh(diff_root_dn))
		#Search for files to patch
		def S_R(data, search, replace):
			if not search:
				_err("There is no find expresion...\n")
				return None
			if not replace:
				_err("There is no replace expresion...\n")
				return None
			try:
				rexFindIt = re.compile(search, re.U|re.M)
			except:
				_err("This is not regular expresion:'%s'\n" % search)
				return None
			matchIt = rexFindIt.search(data)
			if not(matchIt):
				_dbg("This file:'%s' does not contain expresion: %s\n" % (
					fn.replace(diff_tree, ''), repr(search)), dbg_lvl)
				return None
			return re.sub(rexFindIt, replace, data)
		strict_fns = map(lambda n: n[0], strict_rex_list)
		match_fn = re.compile(
			'''^(
			(.+\.(((c|h)((p{2})|(x{2}))?)|(i)|(py)))
			|(.*cmake.*)
			)$''',  re.I|re.X|re.U)
		from os import walk
		from difflib import unified_diff as udiff
		from time import ctime, localtime, strftime
		ud_data = ''
		if debug_level: ls_all_fn = []
		for findRoot, fDir, findFiles in walk(diff_root_dn):
			if not findFiles:
				continue
			for base_fn in findFiles:
				fn = '/'.join((findRoot, base_fn))
				if debug_level: ls_all_fn.append(fn)
				if not(match_fn.match(base_fn)):
					continue
				while ph.islink(fn):
					link_target = ph.realpath(ph.expanduser(rlnk(fn)))
					fn = link_target
				if not(ph.isfile(fn)):
					_err("This file does not exist:'%s'\n" % fn)
					return
				diffNew, diffOld = fn, fn+'.old'
				diffOldInTree, diffNewInTree = diffOld.replace(diff_tree, ''), diffNew.replace(diff_tree, '')
				if ph.isfile(diffOld):
					_err("Seems to diff generation already was performed…\nOld file found:'%s'\n" % diffOld)
					#ls_fn = None
					return
				dbg_lvl = (2, 1)[base_fn in dbg_files]
				hFile = open(fn, 'r')
				if not(hFile):
					_p("Can not open this file:'%s'\n" % fn)
					return
				data = dataCp = hFile.read()
				hFile.close()
				_dbg("Readed file:'%s'\n" % fn, dbg_lvl)
				if base_fn in strict_fns:
					idx = strict_fns.index(base_fn)
					search, replace = strict_rex_list[idx][1:]
					new_data = S_R(data, search, replace)
					if new_data:
						data = new_data
						_dbg("Strict file:'%s'\n" % fn, 1)
				for search, replace in rename_rex_list:
					new_data = S_R(data, search, replace)
					if not(new_data):
						continue
					data = new_data
				if data != dataCp:
					ud_data += '\n'.join(udiff(dataCp.splitlines(), data.splitlines(),
						fromfile=diffOldInTree, tofile=diffNewInTree,
						fromfiledate=strftime("%Y-%m-%d %H:%M:%S.%s", localtime(ph.getmtime(fn))),
						tofiledate=strftime("%Y-%m-%d %H:%M:%S.%s"), n=3, lineterm=''))+'\n'
					'''
					cp(diffNew, diffOld)
					ls_fn.append((diffOldInTree, diffNewInTree))
					hFile = open(fn, 'w')
					if not(hFile):
						_err("Can't write to file:'%s'\n" % fn)
						return
					hFile.write(data)
					hFile.close()
					'''
					_p("Modified file:'%s'\n" % fn)
				else:
					_dbg("File not touched:'%s'\n" % fn, dbg_lvl)
		if ud_data:
			to_fn = 
			hFile = open(output_fn, 'w')
			#hFile = open(unp_dir+'alternative.patch', 'w')
			hFile.write(ud_data)
			hFile.close()
		if debug_level:
			hFile = open(unp_dir+'diff_search_test.txt', 'w')
			hFile.write(("Found %d files:\n" % len(ls_all_fn))+'\n'.join(ls_all_fn)+'\n')
			hFile.close()

	'''
	def call(it, cmd, echo=True):
		from subprocess import Popen, PIPE, STDOUT
		from shlex import split as shs
		if echo:
			print("> %s" % cmd)
		proc = Popen(
			shs(cmd),
			stdout=PIPE,
			stderr=PIPE)
		result, stderr = proc.communicate()
		return proc.returncode, result, stderr

	def diff(it):
		from os import getcwd as pwd, chdir as cd
		if not(diff_root_dn):
			_err("Empty diff_root_dn…\n")
			return
		if not(output_fn):
			_err("Empty output_fn…\n")
			return
		if not(ls_fn):
			_err("Empty ls_fn…\n")
			return
		diff_NoDiff = 0
		diff_Found = 1
		diff_Error = 2
		diff_data_out = ''
		_pwd = pwd()
		cd(diff_root_dn)
		for diffOld, diffNew in ls_fn:
			retcode, diffData, err = it.call("diff -u %s %s" % (diffOld, diffNew))
			_dbg("retCode: %i" % retcode, 1)
			_dbg(", diff data:\n%s" % diffData, 2)
			_dbg("\n", 1)
			if retcode==diff_Found:
				diff_data_out += diffData
		cd(_pwd)
		if diff_data_out:
			output_dn = ph.dirname(output_fn)
			if not(ph.isdir(output_dn)):
				makedirs(output_dn)
			hFile = open(output_fn, 'w')
			if not(hFile):
				_err("Can't write to File:'%s'\n" % output_fn)
				return
			hFile.write(diff_data_out)
			hFile.close()
			_p("Writen File:'%s'\n" % output_fn)
	'''

if __name__=='__main__':
	x = Patcher()

References