def Quotient(d, ratio): # Ignore a requested ratio of 1, as any pair of resistors will work if ratio == 1: out("Quotient cannot be 1") exit(1) d["resistances"], t, Ratio = set(), d["-t"], float(ratio) for R1, R2 in combinations(d["R"], 2): q1 = R1/R2 q2 = 1/q1 if (1 - t)*Ratio <= q1 <= (1 + t)*Ratio: d["resistances"].add((q1, R1, R2)) elif (1 - t)*Ratio <= q2 <= (1 + t)*Ratio: d["resistances"].add((q2, R2, R1)) # Print report res = list(d["resistances"]) if not res: out("No resistor combinations that meet tolerance") return res.sort() out("Desired ratio = ", ratio, ", tolerance = ", sig(d["-t"]*100, 2), "%", sep="") out() out("% dev from") out("desired ratio R1 R2") out("------------- ---------- ----------") for val, r1, r2 in res: dev = 100*((val - Ratio)/Ratio) pct = sig(dev, 2) if dev >= 0: pct = " " + pct R1, R2 = fp.engsi(r1), fp.engsi(r2) if not dev: fg(highlight) out(" {0:10} {1:^10} {2:^10}".format(pct, R1, R2)) normal()
def Rename(fn, d): '''Rename the file named fn to all upper or lower case. Also append the tuple (oldname, newname) to let us write a command to reverse the renamings made. NOTE: we don't save the commands to undo directory name changes because there are cases where it's not easy to recover. ''' new_name = GetNewName(fn, d) is_dir = os.path.isdir(fn) arrow, s = "-->", "/" if is_dir else "" msg = "mv '{}{}' {} '{}{}'".format(fn, s, arrow, new_name, s) if fn != new_name: if is_dir and os.path.isdir(new_name): print("Can't " + msg + ":", file=sys.stderr) print(" Directory already exists", file=sys.stderr) elif os.path.isfile(fn) and os.path.isfile(new_name): print("Can't " + msg + ":", file=sys.stderr) print(" File already exists", file=sys.stderr) if d["-x"] or d["-X"]: try: os.rename(fn, new_name) s = msg.replace(arrow, "") if not is_dir: d["log"].append((fn, new_name)) except os.error: c.fg(c.lblue) print("Couldn't {}".format(msg)) c.normal() else: if is_dir: c.fg(c.lred) print(msg) c.normal()
def Divider(d, ratio): d["divider"] = set() # First check using equal resistors for R in d["R"]: Div(d, float(ratio), R, R) for R1, R2 in combinations(d["R"], 2): Div(d, float(ratio), R1, R2) # Print report div = list(d["divider"]) if not div: out("No divider can be made") return div.sort() out("Voltage divider with ratio = ", ratio, ", tolerance = ", sig(d["-t"]*100, 2), "%", sep="") out() out("% dev from") out("desired ratio R1 R2 Total Res.") out("------------- ---------- ---------- ----------") for rat, r1, r2 in div: dev = 100*((rat - float(ratio))/float(ratio)) pct = sig(dev) if dev >= 0: pct = " " + pct R1, R2, R = fp.engsi(r1), fp.engsi(r2), fp.engsi(r1 + r2) if not dev: fg(highlight) out(" {0:10} {1:^10} {2:^10} {3:^10}".format(pct, R1, R2, R)) normal()
def HoleBasic(D, d): '''D is hole size in inches. ''' shaft_size_in = D shaft_size_mm = D * in2mm print("Hole size is basic:") hole_size_in = float(D) hole_size_mm = in2mm * D print(''' Shaft size Clearance in mm mils mm ------- -------- ----- ------ '''[1:-1]) for name, constant, allowance in fits: correction = (allowance * hole_size_in + constant) / 1000 shaft_size_in = hole_size_in + correction shaft_size_mm = shaft_size_in * in2mm clearance_mils = (hole_size_in - shaft_size_in) * 1000 clearance_mm = clearance_mils * in2mm / 1000 s = " %-18s %10.4f %10.3f" % (name, shaft_size_in, shaft_size_mm) print(s, end=" ") s = "%8.1f %8.2f" % (clearance_mils, clearance_mm) color.fg(interference if clearance_mm < 0 else clearance) print(s) color.normal()
def Execute(cmd, d): '''cmd is of the form (src, dest, cmdlist) where src is the source file, dest is the destination file, and cmdlist is the set of commands to execute if src is newer than dest. ''' src, dest, cmdlist = cmd # Get last modification times try: tm_src = os.stat(src).st_mtime tm_dest = os.stat(dest).st_mtime except Exception as e: msg = "Couldn't get modification times for '%s' or '%s'" c.fg(c.yellow) print(msg % (src, dest)) c.normal() return if tm_src <= tm_dest: return # Execute commands because source is newer than destination print("'%s' is newer than '%s' [%s]" % (src, dest, GetTime(d))) for cmd in cmdlist: if d["-n"]: print("Dry run: ", cmd, "[%s]" % GetTime(d)) else: status = os.system(cmd) if status: c.fg(lred) print("'%s' returned nonzero status" % cmd) c.normal()
def Resistance(d, resistance): d["resistances"] = set() # First see if we have an exact match if resistance in d["R"]: d["resistances"].add((resistance, "e", resistance, 0)) else: # First check using equal resistors for R in d["R"]: Res(d, resistance, R, R) for R1, R2 in combinations(d["R"], 2): Res(d, resistance, R1, R2) res = list(d["resistances"]) if not res: out("No resistor combinations that meet tolerance") return # Check if we have too many entries; if so, whittle down the list to # the closest N. clipped = False if len(res) > d["-n"]: # Sort by absolute value of tolerance tol = lambda tgt, val: abs(val - tgt)/val r = [(tol(resistance, i[0]), i) for i in res] # Decorate with abs val r.sort() res = [i[1] for i in r[:d["-n"]]] clipped = True # Print report res.sort() out("Desired resistance = ", d["desired"], " = ", sig(d["res"]) + ", tolerance = ", sig(d["-t"]*100, 2), "%", sep="") if clipped: out("Closest %d matches shown" % d["-n"]) out() out("% dev from") out("desired res. R1 R2 Connection") out("------------- ---------- ---------- ----------") for val, c, r1, r2 in res: dev = 100*((val - resistance)/resistance) pct = sig(dev, 2) if dev >= 0: pct = " " + pct R1, R2 = fp.engsi(r1), fp.engsi(r2) conn = {"s":"series", "p":"parallel", "e":"exact"}[c] if (d["-p"] and c == "s") or (d["-s"] and c == "p"): continue if not dev: fg(highlight) if c == "e": out(" {0:10} {1:^10} {2}".format(pct, R1, conn)) else: out(" {0:10} {1:^10} {2:^10} {3}".format(pct, R1, R2, conn)) normal()
def PrintMatch(s, d, start, end, isdir=False): '''For the match in s, print things out in the appropriate colors. ''' if isdir: c.fg(c_dir) else: c.fg(c_plain) out(s[:start]) c.fg(c_match) out(s[start:end]) if isdir: c.fg(c_dir) else: c.fg(c_plain)
def CalculateFit(cmdline, D, d): '''hole_size_inches is diameter of hole in inches. d is the settings dictionary. ''' Dmm = D * in2mm print("Diameter = " + cmdline) print(" = %.4f" % D, "inches") print(" = %.3f" % Dmm, "mm") if have_color: print(" " * 20, "Color coding: ", end=" ") color.fg(interference) print("interference", end=" ") color.fg(clearance) print("clearance") color.normal() else: print() HoleBasic(D, d) ShaftBasic(D, d)
def EraseFiles(project, info, d): '''Erase this project's destination files. project is project's name like 'elec/bnc'. info is d["data"][project]. ''' d["top_level_dirs"].add(os.path.split(project)[0]) if d["-F"]: # Force removal of directory and all files, even those that # were not copied by this script. shutil.rmtree(project, ignore_errors=True) return subdirs = set() # Keep track of subdirectories for src, dest in info["files"]: destfile = os.path.join(project, dest) try: subdirs.add(os.path.split(destfile)[0]) if os.path.isfile(destfile): os.remove(destfile) if not d["-q"]: print("Removed %s" % destfile) except Exception: c.fg(c.lred) print("Couldn't remove '%s'" % destfile) c.normal() # Remove subdirectories for subdir in subdirs: try: os.rmdir(subdir) if not d["-q"]: print("Removed directory %s" % subdir) except Exception: if os.path.isdir(subdir): print("Couldn't remove directory %s" % subdir) # All files erased, now remove project directory. An exception # means the directory probably isn't empty. try: os.rmdir(project) if not d["-q"]: print("Removed directory %s" % project) except Exception: if os.path.isdir(project): print("Couldn't remove directory %s" % project)
def MakeSoftlinks(d): Message("Making softlinks", c.lblue) for src, dest in softlinks: if not os.path.isfile(src): Error("'%s' is missing in MakeSoftlinks()" % src) if os.path.islink(dest): os.remove(dest) elif os.path.isfile(dest): Error("'%s' exists in MakeSoftlinks()" % dest) try: abs_src_dir = os.path.abspath(src) dest_dir, dest_file = os.path.split(dest) if not dest_dir: Error("ln -s '%s' '%s' on empty dir" % (src, dest)) curdir = os.getcwd() try: # Remove any existing link or file os.remove(dest) except OSError: pass # Change to the destination diretory so we can get a # relative path to the file we want to point to. if dest_dir: os.chdir(dest_dir) # Get the source directory relative to current directory relsrc = os.path.relpath(abs_src_dir) # Make the link os.symlink(relsrc, dest_file) if dest_dir: os.chdir(curdir) c.fg(c.lblue) print(" ln -s '%s' <-- '%s'" % (src, dest)) c.normal() except Exception as e: msg = ["Couldn't make softlink '%s' --> '%s'" % (src, dest)] msg += [" %s" % e] Error('\n'.join(msg))
def OO_PictureFiles(d): '''Check each file in oo_files for pictures; print out any that are missing (these then need to be added to the project's data). Note they are printed out in 'File(...)' form, allowing them to be inserted in this script's data verbatim. ''' error = False Message("Checking OO picture files", c.yellow) for path in oo_files: if not os.path.isfile(path): Error("OO_PictureFiles(): '%s' doesn't exist" % path) image_files = loo.GetImages(path) # Ignore embedded files # The returned container has elements of (path, state) where path # is relative to the OO doc's location and state is one of # "", "notrel", or "missing". Print out messages about notrel # or missing files. dir, name = os.path.split(path) # Check each picture file missing = [] for picfile, state in image_files: if state == "missing": missing.append((picfile, state)) elif state == "notrel": Error("'%s' notrel in '%s'" % (picfile, path)) if missing: if not error: print() c.fg(c.lred) print("One or more OO files missing images:") c.normal() print("\n") print("OO file '%s' missing images:" % path) for picfile, state in missing: print(' File("%s")' % picfile) error = True if error: exit(1)
def PrintReport(d): '''Note we'll put a '/' after directories to flag them as such. ''' D = d["search"] if d["-s"]: # Print things in sorted form, directories first. dirs, files = [], [] # Organize by directories and files. Note you need to use keys() # to get the original insertion order for i in D.keys(): if D[i]: dirs.append(i) else: files.append(i) c.fg(c_plain) dirs.sort() files.sort() if not d["-d"] and not d["-f"]: # Both directories and files for i in dirs: PrintMatches(i + "/", d, isdir=True) for i in files: PrintMatches(i, d) else: if d["-d"]: # Directories only for i in dirs: PrintMatches(i + "/", d, isdir=True) else: # Files only for i in files: PrintMatches(i, d) else: # Print things as encountered by os.walk for i in D.keys(): if (d["-f"] and D[i]) or (d["-d"] and not D[i]): continue PrintMatches(i + "/" if D[i] else i, d, isdir=D[i]) c.fg(c_norm)
def PrintMatches(s, d, isdir=False): '''Print the string s and show the matches in appropriate colors. Note that s can end in '/' if it's a directory. We handle this case specially by leaving off the trailing '/'. ''' if d["-f"] and not d["-d"]: # Files only -- don't print any matches in directory dir, file = os.path.split(s) out(dir) if dir and dir[:-1] != "/": out("/") s = file while s: if isdir and s[-1] == "/": mo = d["regex"].search(s[:-1]) else: mo = d["regex"].search(s) if mo and d["-c"]: PrintMatch(s, d, mo.start(), mo.end(), isdir=isdir) s = s[mo.end():] else: # If the last character is a '/', we'll print it in color # to make it easier to see directories. if s[-1] == "/": out(s[:-1]) c.fg(c_dir) out("/") else: try: out(s) except IOError: # Caused by broken pipe error when used with less exit(0) s = "" c.fg(c_plain) out(nl)
def PrintResults(files, d): '''files is a dictionary keyed by Mercurial status letter. d is the options dictionary. ''' assert len(files) > 0 normal = (white, black) names = { "A": ("Added files:", (lgreen, black)), "C": ("Clean files:", (white, black)), "I": ("Ignored files:", (cyan, black)), "M": ("Modified files:", (yellow, black)), "R": ("Removed files:", (lwhite, red)), "!": ("Missing files:", (lmagenta, black)), "?": ("Untracked files:", (lred, black)), } for key in "ICRAM!?": color = names[key][1] c.fg(color) if key in files and files[key]: PrintItems(files[key], names[key][0], d) c.fg(normal) c.fg(normal)
def Message(s, fg, bg=c.black): c.fg(fg, bg) print(s) c.normal()
def Dump(opt): '''Print a listing to stdout. ''' Colors = { 0 : { "name" : c.yellow, "files" : c.lmagenta, "softlinks" : c.lblue, "todo" : c.lred, "srcdir" : c.lgreen, }, 1 : { "name" : c.gray, "files" : c.gray, "softlinks" : c.gray, "todo" : c.gray, "srcdir" : c.gray, }, } projects = list(data.keys()) projects.sort() for project in projects: d = data[project] if d["ignore"] is not None and not opt["-i"]: continue if d["ignore"] is not None: C = Colors[1] c.normal(c.gray, c.black) else: C = Colors[0] c.normal(c.white, c.black) c.fg(C["name"]) print(project, end="") c.normal() if d["ignore"] is not None: print(" ignored: %s" % d["ignore"]) else: print() keys = list(d.keys()) keys.sort() for k in keys: if k == "files": c.fg(C["files"]) print(" Files:") for f in d["files"]: c.fg(C["files"]) if isinstance(f, (list, tuple)) and len(f) == 1: print(" %s -> %s" % (f, f)) elif isinstance(f, str): print(" %s -> %s" % (f, f)) else: print(" %s -> %s" % tuple(f)) c.normal() elif k == "softlinks": if not d[k]: continue c.fg(C["softlinks"]) print(" Softlinks:") for f in d["softlinks"]: c.fg(C["softlinks"]) print(" %s -> %s" % tuple(f)) c.normal() elif k == "descr": print(" %s =" % k) t = dedent(d[k]) print(tw.fill(t)) #for line in t.strip().split("\n"): # print(" %s" % line) elif k == "todo": c.fg(C["todo"]) if d[k] is not None: print(" %s = %s" % (k, d[k])) c.normal() elif k == "srcdir": print(" srcdir = ", end="") c.fg(C["srcdir"]) print(d[k]) c.normal() elif k == "ignore": pass elif k in ("category", "python3", "tests"): print(" %s = %s" % (k, d[k])) else: Error("Unhandled category %s" % k) print(" %s = %s" % (k, d[k])) print() c.fg(c.white, c.black) print("%d total packages" % len(data))
def Error(msg, status=1): c.fg(c.lred) print(msg) c.normal() exit(status)
def PrintSize(size, stream, d): if d["-c"]: c.fg(GetColor(size)) print("%d" % size, file=stream, end="") if d["-c"]: c.normal()
on_windows = True cygwin = "c:/cygwin" if on_windows else "" # If we need to launch a file with its registered app, we use the following # command. if on_windows: start = Join(cygwin, "/usr/bin/cygstart") else: start = "exo-open" # On Linux # If a package is to be made with the -z option, this directory is where # the packages will reside (it's separate from the repository). package_dir = cygwin + "/home/Don/hobbyutil_packages" # Escape sequences for colors fz = c.fg(c.lblue, s=True) # Frozen st = c.fg(c.lred, s=True) # Stale no = c.normal(s=True) # Normal color # Text wrapper tw = textwrap.TextWrapper() tw.width = int(os.environ.get("COLUMNS", 80)) - 5 tw.replace_whitespace = True tw.fix_sentence_endings = True tw.initial_indent = tw.subsequent_indent = " " * 4 # Names of the output directories output_directories = set() # Name of the project list markdown file pl = "project_list"
def FG(arg): '''This calls C.fg(), but only if d["-c"] is True. This avoids having escape sequences sent to stdout. ''' if d["-c"]: C.fg(arg)
def ProcessFile(oofile, d): '''Print out any linked image files in the Open Office file oofile. d is the options directory. ''' if not os.path.isfile(oofile): err("'%s' is not a file%s" % (oofile, nl)) return colors = { "missing" : (c.lwhite, c.red), "notrel" : (c.lwhite, c.magenta), "embedded" : c.lgreen, } image_files = GetImages(oofile, ignore_embedded=not d["-e"]) if not image_files and not d["-m"]: # List the file out("%s%s" % (oofile, nl)) return some_missing = any([i[1] == "missing" for i in image_files]) some_notrel = any([i[1] == "notrel" for i in image_files]) some_embedded = any([i[1] == "embedded" for i in image_files]) if d["-m"] and not (some_missing or some_notrel): # If we're only supposed to list missing stuff and this OO # file had neither, then return. return if d["-l"]: # Only list the OO files, not their contents. We'll color # code them to indicate missing or notrel content. "missing" # takes precedence over "notrel" and both take precedence over # "embedded". if some_embedded: c.fg(colors["embedded"]) if some_notrel: c.fg(colors["notrel"]) if some_missing: c.fg(colors["missing"]) out(oofile) c.normal() out(nl) return if d["-m"]: # image_files can be empty or only contain embedded files, in # which case we should return. if not image_files: return if all([IsEmbeddedImage(i[0]) for i in image_files]): return c.normal() out(oofile) out(nl) for name, state in image_files: if IsEmbeddedImage(name) and not d["-e"]: continue if d["-m"] and not state: continue out(" "*4) out(name) out(" ") if state in ("missing", "notrel", "embedded"): c.fg(colors[state]) out("[%s]" % state) c.normal() out(nl)