def p_file_open(fn, mode = 'r'): """ open files if file exists - error otherwise """ if os.path.isfile(fn): try: f_open = open(fn, mode) except EnvironmentError: msg = (p_here('', 2) + 'unable to open file : >' + fn + '< EnvironmentError!') p_log_this(msg, 'error') ; print msg else: msg = (p_here('', 2) + ' file : >' + fn + '< open for ' + mode) p_log_this(msg) return f_open elif (mode == 'w'): open(fn, 'w').close() try: f_open = open(fn, mode) except EnvironmentError: msg = (p_here('', 2) + 'unable to open file : >' + fn + '< EnvironmentError!') p_log_this(msg, 'error') ; print msg else: msg = (p_here('', 2) + ' file : >' + fn + '< open for ' + mode) p_log_this(msg) return f_open else: msg = (' file : >' + fn + '< does not exist') p_log_this(msg, 'error'); print msg
def p_main_cfg_create_hash(): """ called by >pyprogen.py< after >create_ca_parser< is called, i.e after a new >y_main_TimeStamp.cfg< is written. Calculates hash of defaults & creates section >signature< with items: >timestamp< and >hash< """ p_log_this('cfg_path_tmp: ' + p_glbls.cfg_path_tmp) parser = ConfigParser.SafeConfigParser(allow_no_value=True) cfg_file = parser.read(p_glbls.cfg_path_tmp) try: # read defaults and calc their hash defaults = parser.items("defaults") # read section "defaults" defaults_str = '' for key_val in defaults: # type(defaults) == list[tuple, tuple ...] defaults_str = defaults_str + key_val[0] + key_val[1] hash_md5 = hashlib.md5() hash_md5.update(defaults_str) # calc hash hash_of_defaults = hash_md5.hexdigest() except ConfigParser.NoSectionError: p_log_this("No section: 'defaults' in: >" + p_glbls.cfg_path_tmp + '< !') return # to >y_main.cfg< add a section "signature" with hash & time_stamp parser.add_section("signature") parser.set("signature", "hash", hash_of_defaults) parser.set("signature", "timestamp", p_glbls.date_time_str) parser.write(open(p_glbls.cfg_path_tmp, "w"))
def p_main_was_modified(outfile_path): """ check if y_main.py was modified (== hash is different) """ old_main_file = p_utils.p_file_open(outfile_path, mode = 'r') if not old_main_file: return False with old_main_file: lines = old_main_file.readlines() p_utils.p_file_close(old_main_file) date_line = lines[0] # first line contains date-time string hash_line = lines[1] # second line contains hash (of lines 3 to n-1) at moment of generating # calc hash of code, i.e. of hash all lines, ignoring first 2 lines and last line: code_to_hash = '' for line in lines[2:-1]: code_to_hash = code_to_hash + line hash_md5 = hashlib.md5() hash_md5.update(code_to_hash) # calc hash hash_of_code = hash_md5.hexdigest() old_hash_str = rgx_get_old_hash_strg(hash_line) # get hash at moment of generating if old_hash_str != hash_of_code: # hashes are identical? mssge = ('>' + outfile_path + '< has been modified') p_log_this (mssge) # ; print mssge return True else: p_log_this ('>' + outfile_path + '< + is unchanged') return False
def p_file_exists (fn, print_message = False): """ open files if file exists - error otherwise """ if os.path.isfile(fn): return True else: msg = (' file : >' + fn + '< does not exist') p_log_this(msg, 'error') if print_message: print msg return False
def p_write_code (input_dict, outfile_fn, outfile_path): """ writes >input_dict< to outfile """ p_log_this('writing: ' + outfile_path) with open(outfile_path, 'w') as outfile: # outfile.write('# -*- coding: utf-8 -*-\n') outfile.write('# ' + p_glbls.date_time_str + ' generated by: >pyprogen.py<\n') #for key, patt in patts.iteritems(): for key, patt in sorted(input_dict.iteritems()): outfile.write(patt) outfile.write('# ' + p_glbls.date_time_str)
def rgx_get_old_hash_strg(hash_line): """ extract originally calculated hash from inp_line / thx to: http://txt2re.com""" re1='(>)' # Any Single Character 1 re2='(([a-z0-9]*))' # Alphanum 1 re3='(<)' # Any Single Character 2 rg = re.compile(re1+re2+re3,re.IGNORECASE|re.DOTALL) m = rg.search(hash_line) if m: c1=m.group(1) alphanum1=m.group(2) c2=m.group(3) # print c1 ; print alphanum1 ; print c2 old_hash_str = alphanum1 else: old_hash_str = 'NO_HASH_FOUND' p_log_this(old_hash_str) return old_hash_str
def p_main(): """ if (>y_main.py< exists && >y_main.py< was modified) => save it. else: => create new >y_main.py< """ outfile_fn = p_glbls.prog_name # fn and path of >y_main.py< outfile_path = os.path.join(p_glbls.dir_main, outfile_fn) p_log_this('creating: ' + outfile_path) # Make new code: # make txt for >if<'s for >opt_arg_vars< of commandline txt = ' '*4 + '# optional args(ConfArgParser):\n' for arg in p_glbls.opt_arg_vars: # txt = txt + ' '*4 + 'if ' + 'xx_glbls.arg_ns.' + arg + ' == "something":\n' txt = txt + ' '*4 + 'if ' + 'xx_glbls.arg_ns.' + arg + ' == xx_glbls.arg_ns.' + arg + ':\n' txt = txt + ' '*8 + 'eval_arg(xx_glbls.arg_ns.' + arg +')\n' txt = txt + '\n' patterns.y_main[10] = txt # add txt to pattern # generate correct var names y_main = p_subst_vars_in_patterns (patterns.y_main) # now >y_main< is complete. => calculate hash for generated program: code = '' # put all code parts together in ane string. for key, chunk in sorted(y_main.iteritems()): code = code + chunk # print '=' *40 ; print len(code) ;print '=' *40 hash_md5 = hashlib.md5() hash_md5.update(code) # calculate hash of code hash_of_code = hash_md5.hexdigest() # here (>hash_of_mytext<) it is # Add hash as heading line to the code: code_dict = dict() # p_write_code wants dict as input code_dict[1] = '# >' + hash_of_code + '< \n' # second line of y_main.py code_dict[2] = code # # if existing >y_main.py< was modified => new >y_main.py< gets timestamp in fn if p_main_was_modified(outfile_path): outfile_path = outfile_path[:-3] + '_' + p_glbls.date_time_str + '.py' # finally write code (adding timestamp in first line & lastline) p_write_code (code_dict, outfile_fn, outfile_path) # write >y_main(_+/-timestamp.py<
def p_globals(): """ creates ./y_main/lib/y_glbls.py """ # fn and path of >y_glbls.py< outfile_fn = p_glbls.glbls_fn outfile_path = os.path.join(p_glbls.dir_lib, p_glbls.glbls_fn) p_log_this('creating: ' + outfile_path) txt = ' '*4 + '# optional args(ConfArgParser):\n' for arg in p_glbls.opt_arg_vars: txt = txt + ' '*4 + 'arg_ns.' + arg + ' = None\n' txt = txt + ' '*4 + '# positional args(ConfArgParser):\n' for arg in p_glbls.pos_arg_vars: txt = txt + ' '*4 + 'arg_ns.' + arg + ' = None\n' txt = txt + ' '*4 + 'return arg_ns\n' patterns.y_glbls[04] = txt txt = '' patterns.y_glbls[96] = txt # p_subst(patterns.y_glbls, outfile_fn, outfile_path) code = p_subst_vars_in_patterns (patterns.y_glbls) p_write_code (code, outfile_fn, outfile_path)
def p_dir_is_abs(dir): """ checks if dir is abs dir """ dir = os.path.normpath(dir) if (os.path.isabs(dir)): mssg_1 = (' dir: >' + dir + '< is absolute, should be relative!') mssg_2 = (' please change dir: >' + dir + '< to relative subdir (i.e. ./log) ') mssg_3 = (' .... exiting!') print mssg_1 + mssg_2 + mssg_3 p_log_this(mssg_1); p_log_this(mssg_2) ; p_log_this(mssg_3) p_exit() # exit ! if (dir == ''): dir = '.' return dir
def p_dir_make(dir): """ makes dir if dir """ dir = os.path.normpath(dir) if not os.path.exists(dir): try: os.makedirs(dir) p_log_this(' creating dir: ' + dir ) except IOError: mssge = (' creating dir: ' + dir + ' failed!') p_log_this(mssge) ; print mssge else: p_log_this(' dir exists : >' + dir + '<') return dir
def p_ConfArgParser(conf_file_fn='./pyprogen.conf'): """ creates >y_CAParser.py<; executes it, to generate a conf file >y_main.cfg< for >y_main.py< """ p_log_this(conf_file_fn) opt_args = [] # local list of opt-args pos_args = [] # local list of pos-args # >p_ConfArgParser< sets vars in p_glbls. ... for later use in >p_code.p_globals< p_glbls.opt_arg_vars = [] # list (in p_glbls) of opt-args p_glbls.pos_arg_vars = [] # list (in p_glbls) of pos-args opt_arg_lines = [] # lines with optional args pos_arg_lines = [] # lines with positional args # regex: searching for whitespace rgx_whitespace = re.compile(r'\s+') # regex: searching for optional (== non-positional) args: rgx_minus = make_regex_opt_arg_minus() # regex vs. >('-f',< rgx_minus_minus = make_regex_opt_arg_minus_minus() # regex vs. >('--foo',< # regex: searching for optional (== non-positional) args: rgx_pos_arg = make_regex_pos_arg() # regex vs. >('bar',< # in conf_file search for (non comment) lines with positional / optional args with open(conf_file_fn, 'r') as infile: for line in infile: line.lstrip() if not line.startswith('#'): # remove whitespace lines: line_test = re.sub(rgx_whitespace, '', line) if line_test: match_minus_minus = rgx_minus_minus.search(line) match_minus = rgx_minus.search(line) match_pos_arg = rgx_pos_arg.search(line) if match_minus_minus: group_0 = match_minus_minus.group(0)[:-1].lstrip() if len (group_0) > 2: # p_glbls.opt_arg_vars.append(group_0[3:]) opt_args.append(group_0[1:]) opt_arg_lines.append(line) elif match_minus: group_0 = match_minus.group(0)[:-1].lstrip() if len (group_0) > 1: # p_glbls.opt_arg_vars.append(group_0[2:]) opt_args.append(group_0[1:]) opt_arg_lines.append(line) elif match_pos_arg: group_0 = match_pos_arg.group(0)[:-1].lstrip() if len (group_0) > 2: # p_glbls.pos_arg_vars.append(group_0[1:]) pos_args.append(group_0[1:]) pos_arg_lines.append(line) # strip '-' or '--' from opt_args and copy them to >p_glbls.opt_arg_vars< for arg in opt_args: p_glbls.opt_arg_vars.append(arg.lstrip('-')) # copy opt_args to >p_glbls.opt_arg_vars< for arg in pos_args: p_glbls.pos_arg_vars.append(arg) # generate lines with pos args like: >parser.add_argument('bar', type=file)< txt = '' for line in pos_arg_lines: txt = txt + ' ' + line # + '\n' # generate lines with pos args like: >parser.add_argument('-f', '--foo', ...)< for line in opt_arg_lines: txt = txt + line # + '\n' patterns.CA_Parser[04] = txt # log positional and optional arguments for arg in pos_args: p_log_this('pos. arg: ' + arg) for arg in opt_args: p_log_this('opt. arg: ' + arg) # write y_CAParser.py == ConfArgParser for new program p_glbls.CAParser_fn = p_glbls.prefix + 'CAParser.py' # >y_CAParser.py< p_glbls.CAParser_path = os.path.join(p_glbls.dir_lib, p_glbls.CAParser_fn ) outfile_fn = p_glbls.CAParser_fn outfile_path = p_glbls.CAParser_path code = p_subst_vars_in_patterns (patterns.CA_Parser) p_code.p_write_code (code, outfile_fn, outfile_path)
def p_read_ini(dir_cfg='.', cfg_fn='new_prog.ini'): """ reads defaults for generated program: name ...""" # http://www.karoltomala.com/blog/?p=622 path = os.path.abspath(__file__) dir_path = os.path.dirname(path) # print 'p_read_ini: dir_path = ', p_utils.p_act_dir_path() # print 'p_read_ini: dir_path = ', dir_path # print p_glbls.__file__ p_log_this() cfg_path = os.path.join(dir_cfg, cfg_fn) # cfg_path_tmp of >pyprogen.py< ! cfg_path = os.path.normpath(cfg_path) # not of >y_main.py< !! parser = ConfigParser.SafeConfigParser(allow_no_value=True) p_log_this('cfg_path_tmp: ' + cfg_path) cfg_file = parser.read(cfg_path) p_log_this('cfg file: ' + str(cfg_file)) # p_glbls.prog_name try: p_glbls.prog_name = parser.get("properties", "prog_name") p_log_this('prog_name = ' + p_glbls.prog_name) if (len(p_glbls.prog_name) < 4): p_glbls.prog_name = p_glbls.prog_name + '.py' p_log_this(' =>' + p_glbls.prog_name) if ((string.lower(p_glbls.prog_name[-3:])) <> '.py'): p_glbls.prog_name = p_glbls.prog_name + '.py' p_log_this(' =>' + p_glbls.prog_name) except ConfigParser.NoOptionError: p_glbls.prog_name = 'z_main.py' p_log_this('no >prog_name< in: ' + cfg_path + ' !') p_log_this('prog_name set to: ' + p_glbls.prog_name) # p_glbls.prog_path p_glbls.prog_path = os.path.normpath(p_glbls.prog_name[:-3]) # print 'p_read_ini: p_glbls.prog_path = ', p_glbls.prog_path p_log_this("prog_path = " + p_glbls.prog_path) # p_glbls.prefix try: p_glbls.prefix = parser.get("properties", "prefix") p_log_this('prefix = ' + p_glbls.prefix) if (len(p_glbls.prefix) < 2): p_log_this('prefix = ' + p_glbls.prefix) p_glbls.prefix = p_glbls.prog_name[0] + '_' # prefix for generated program p_log_this('prefix set to: ' + p_glbls.prefix) except ConfigParser.NoOptionError: p_glbls.prefix = p_glbls.prog_name[0] + '_' # prefix for generated program p_log_this('prefix set to: ' + p_glbls.prefix) # p_glbls.date_time_str p_glbls.date_time_str = p_utils.p_make_act_date_str()
def p_main_cfg_check_hash(): """ called by >pyprogen.py< after >create_ca_parser< has been called and after p_main_cfg_create_hash() has added hash to: >./y_main/cfg/y_main_TimeStamp.cfg< if not (>y_main.cfg< exists) move >y_main_TimeStamp.cfg< to >y_main.cfg< return elsif (>y_main.cfg< was changed): # keep >y_main.cfg<; keep >y_main_TimeStamp.cfg<; return else: move >y_main_TimeStamp.cfg< to >y_main.cfg< """ p_log_this('cfg_path: ' + p_glbls.cfg_path) if not p_utils.p_file_exists (p_glbls.cfg_path): dest_path = p_glbls.cfg_path mssge = ( '>' + p_glbls.cfg_path_tmp + '< renamed to: >' + dest_path + '<') p_log_this (mssge) ; print (mssge) # move source to dest: shutil.move(p_glbls.cfg_path_tmp, dest_path) # p_glbls.cfg_path return parser = ConfigParser.SafeConfigParser(allow_no_value=True) cfg_file = parser.read(p_glbls.cfg_path) try: # read defaults and calc their hash defaults = parser.items("defaults") defaults_str = '' for key_val in defaults: defaults_str = defaults_str + key_val[0] + key_val[1] hash_md5 = hashlib.md5() hash_md5.update(defaults_str) # calc hash act_hash_of_defaults = hash_md5.hexdigest() except ConfigParser.NoSectionError: mssge = ("No section: 'defaults' in: >" + p_glbls.cfg_path + '< !') p_log_this(mssge); print('Error: ' + mssge) return try: # read old hash (and time_stamp) old_hash_of_defaults = parser.get("signature", "hash") timestamp = parser.get("signature", "timestamp") except ConfigParser.NoSectionError or ConfigParser.NoOptionError: if ConfigParser.NoSectionError: p_log_this("No section: 'signature' in: >" + p_glbls.cfg_path + '< !') if ConfigParser.NoOptionError: p_log_this("No option: 'timestamp' or 'hash' in section 'signature' in: >" + p_glbls.cfg_path_tmp + '< !') return if (act_hash_of_defaults == old_hash_of_defaults): print 'section: "signature" in >' + p_glbls.cfg_path + '< unchanged.' dest_path = p_glbls.cfg_path mssge = ( '>' + p_glbls.cfg_path_tmp + '< renamed to: >' + dest_path + '<') p_log_this (mssge) ; print (mssge) # move source to dest: shutil.move(p_glbls.cfg_path_tmp, dest_path) else: print 'section: "signature" in >' + p_glbls.cfg_path + '< has been modified.' print ' => 1) leave >' + p_glbls.cfg_path + '< unchanged.' print ' 2) most recent config file is: >' + p_glbls.cfg_path_tmp + '<.'