Exemplo n.º 1
0
def tests(tests):
    scad_dir = "tests"
    deps_dir = scad_dir + "/deps"
    png_dir = scad_dir + "/png"
    bom_dir = scad_dir + "/bom"
    for dir in [deps_dir, png_dir, bom_dir]:
        if not os.path.isdir(dir):
            os.makedirs(dir)
    doc_name = "readme.md"
    index = {}
    bodies = {}
    times.read_times()
    options.check_options(deps_dir)
    #
    # Make cover pic if does not exist as very slow. Delete it to force an update.
    #
    png_name = "libtest.png"
    scad_name = "libtest.scad"
    if not os.path.isfile(png_name):
        openscad.run(colour_scheme, "--projection=p",
                     "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,50,0,340,500",
                     "--autocenter", "--viewall", "-o", png_name, scad_name)
        do_cmd([
            "magick", png_name, "-trim", "-resize", "1280", "-bordercolor",
            background, "-border", "10", png_name
        ])
    #
    # List of individual part files
    #
    scads = [i for i in sorted(os.listdir(scad_dir)) if i[-5:] == ".scad"]

    for scad in scads:
        base_name = scad[:-5]
        if not tests or base_name in tests:
            print(base_name)
            cap_name = base_name[0].capitalize() + base_name[1:]
            scad_name = scad_dir + '/' + scad
            png_name = png_dir + '/' + base_name + '.png'
            bom_name = bom_dir + '/' + base_name + '.json'

            objects_name = None
            vits_name = 'vitamins/' + base_name + '.scad'
            if is_plural(base_name) and os.path.isfile(vits_name):
                objects_name = vits_name

            locations = [
                ('vitamins/' + depluralise(base_name) + '.scad', 'Vitamins'),
                ('printed/' + base_name + '.scad', 'Printed'),
                ('utils/' + base_name + '.scad', 'Utilities'),
                ('utils/core/' + base_name + '.scad', 'Core Utilities'),
            ]

            for name, type in locations:
                if os.path.isfile(name):
                    impl_name = name
                    break
            else:
                print("Can't find implementation!")
                continue

            vsplit = "M"
            vtype = locations[0][1]
            types = [
                vtype + ' A-' + vsplit[0],
                vtype + ' ' + chr(ord(vsplit) + 1) + '-Z'
            ] + [loc[1] for loc in locations[1:]]
            if type == vtype:
                type = types[0] if cap_name[0] <= vsplit else types[1]

            for t in types:
                if not t in bodies:
                    bodies[t] = []
                    index[t] = []

            body = bodies[type]

            index[type] += [cap_name]
            body += ['<a name="%s"></a>' % cap_name]
            body += ["## " + cap_name]

            doc = None
            if impl_name:
                doc = scrape_code(impl_name)
                blurb = doc["blurb"]
            else:
                blurb = scrape_blurb(scad_name)

            if not len(blurb):
                print("Blurb not found!")
            else:
                body += [blurb]

            if objects_name:
                body += [
                    "[%s](%s) Object definitions.\n" %
                    (objects_name, objects_name)
                ]

            if impl_name:
                body += ["[%s](%s) Implementation.\n" % (impl_name, impl_name)]

            body += [
                "[%s](%s) Code for this example.\n" %
                (scad_name.replace('\\', '/'), scad_name)
            ]

            if doc:
                for thing, heading in [("properties", "Function"),
                                       ("functions", "Function"),
                                       ("modules", "Module")]:
                    things = doc[thing]
                    if things:
                        body += [
                            '### %s\n| %s | Description |\n|:--- |:--- |' %
                            (thing.title(), heading)
                        ]
                        for item in sorted(things):
                            body += [
                                '| ```%s``` | %s |' % (item, things[item])
                            ]
                        body += ['']

            body += ["![%s](%s)\n" % (base_name, png_name)]

            dname = deps_name(deps_dir, scad)
            oldest = png_name if mtime(png_name) < mtime(
                bom_name) else bom_name
            changed = check_deps(oldest, dname)
            changed = times.check_have_time(changed, scad_name)
            changed = options.have_changed(changed, oldest)
            if changed:
                print(changed)
                t = time.time()
                tmp_name = 'tmp.png'
                openscad.run_list(options.list() + [
                    "-D$bom=2", colour_scheme, "--projection=p",
                    "--imgsize=%d,%d" %
                    (w, h), "--camera=0,0,0,70,0,315,500", "--autocenter",
                    "--viewall", "-d", dname, "-o", tmp_name, scad_name
                ])
                times.add_time(scad_name, t)
                do_cmd([
                    "magick", tmp_name, "-trim", "-resize", "1000x600",
                    "-bordercolor", background, "-border", "10", tmp_name
                ])
                update_image(tmp_name, png_name)
                BOM = bom.parse_bom()
                with open(bom_name, 'wt') as outfile:
                    json.dump(BOM.flat_data(), outfile, indent=4)

            with open(bom_name, "rt") as bom_file:
                BOM = json.load(bom_file)
                for thing, heading in [("vitamins", "Module call | BOM entry"),
                                       ("printed", "Filename"),
                                       ("routed", "Filename"),
                                       ("assemblies", "Name")]:
                    things = BOM[thing]
                    if things:
                        body += [
                            '### %s\n| Qty | %s |\n| ---:|:--- |%s' %
                            (thing.title(), heading,
                             ':---|' if '|' in heading else '')
                        ]
                        for item in sorted(things,
                                           key=lambda s: s.split(":")[-1]):
                            name = item
                            desc = ''
                            if thing == "vitamins":
                                vit = item.split(':')
                                name = '```' + vit[0] + '```' if vit[0] else ''
                                while '[[' in name and ']]' in name:
                                    i = name.find('[[')
                                    j = name.find(']]') + 2
                                    name = name.replace(name[i:j], '[ ... ]')
                                desc = vit[1]
                                body += [
                                    '| %3d | %s | %s |' %
                                    (things[item], name, desc)
                                ]
                            else:
                                body += ['| %3d | %s |' % (things[item], name)]
                        body += ['']

            body += ['\n<a href="#top">Top</a>']
            body += ["\n---"]

    with open(doc_name, "wt") as doc_file:
        print('# NopSCADlib', file=doc_file)
        print('''\
An ever expanding library of parts modelled in OpenSCAD useful for 3D printers and enclosures for electronics, etc.

It contains lots of vitamins (the RepRap term for non-printed parts), some general purpose printed parts and
some utilities. There are also Python scripts to generate Bills of Materials (BOMs),
 STL files for all the printed parts, DXF files for CNC routed parts in a project and a manual containing assembly
instructions and exploded views by scraping markdown embedded in OpenSCAD comments, [see scripts](scripts/readme.md). A simple example project can be found [here](examples/MainsBreakOutBox/readme.md).

For more examples of what it can make see the [gallery](gallery/readme.md).

The license is GNU General Public License v3.0, see [COPYING](COPYING).

See [usage](docs/usage.md) for requirements, installation instructions and a usage guide.

<img src="libtest.png" width="100%"/>\n
''',
              file=doc_file)

        print('## Table of Contents<a name="top"/>', file=doc_file)
        print('<table><tr>', file=doc_file)
        n = 0
        for type in types:
            print('<th align="left"> %s </th>' % type, end='', file=doc_file)
            n = max(n, len(index[type]))
        print('</tr>', file=doc_file)
        for i in range(n):
            print('<tr>', file=doc_file, end='')
            for type in types:
                if i < len(index[type]):
                    name = sorted(index[type])[i]
                    print('<td> <a href = "#' + name + '">' + name +
                          '</a> </td>',
                          file=doc_file,
                          end='')
                else:
                    print('<td></td>', file=doc_file, end='')
            print('</tr>', file=doc_file)
        print('</table>\n\n---', file=doc_file)
        for type in types:
            for line in bodies[type]:
                print(line, file=doc_file)
    with open("readme.html", "wt") as html_file:
        do_cmd("python -m markdown -x tables readme.md".split(), html_file)
    times.print_times()
    do_cmd('codespell -L od readme.md'.split())
Exemplo n.º 2
0
def views(target, do_assemblies=None):
    done_assemblies = []
    #
    # Make the target directory
    #
    top_dir = set_config(target)
    target_dir = top_dir + 'assemblies'
    deps_dir = top_dir + "deps"
    bom_dir = top_dir + "bom"
    if not os.path.isdir(target_dir):
        os.makedirs(target_dir)
    if not os.path.isdir(deps_dir):
        os.makedirs(deps_dir)

    times.read_times(target_dir)
    bounds_fname = top_dir + 'stls/bounds.json'
    with open(bounds_fname) as json_file:
        bounds_map = json.load(json_file)
    #
    # Find all the assemblies
    #
    assemblies = bom_to_assemblies(bom_dir, bounds_map)
    for file in os.listdir(target_dir):
        if file.endswith('.png'):
            assembly = file[:-4].replace('_assembled', '_assembly')
            if assembly.endswith('_tn'):
                assembly = assembly[:-3]
            if not assembly in assemblies:
                print("Removing %s" % file)
                os.remove(target_dir + '/' + file)
    #
    # Find all the scad files
    #
    main_blurb = None
    lib_dir = os.environ['OPENSCADPATH'] + '/NopSCADlib/printed'
    for dir in [source_dir, lib_dir]:
        for filename in os.listdir(dir):
            if filename.endswith('.scad'):
                #
                # find any modules with names ending in _assembly
                #
                with open(dir + "/" + filename, "r") as f:
                    lines = f.readlines()
                line_no = 0
                for line in lines:
                    words = line.split()
                    if len(words) and words[0] == "module":
                        module = words[1].split('(')[0]
                        if is_assembly(module):
                            if module in assemblies:
                                #
                                # Scrape the assembly instructions
                                #
                                for ass in flat_bom:
                                    if ass["name"] == module:
                                        if not "blurb" in ass:
                                            ass["blurb"] = blurb.scrape_module_blurb(
                                                lines[:line_no])
                                        break
                                if not do_assemblies or module in do_assemblies:
                                    #
                                    # make a file to use the module
                                    #
                                    png_maker_name = 'png.scad'
                                    with open(png_maker_name, "w") as f:
                                        f.write("use <%s/%s>\n" %
                                                (dir, filename))
                                        f.write("%s();\n" % module)
                                    #
                                    # Run openscad on th created file
                                    #
                                    dname = deps_name(deps_dir, filename)
                                    for explode in [0, 1]:
                                        png_name = target_dir + '/' + module + '.png'
                                        if not explode:
                                            png_name = png_name.replace(
                                                '_assembly', '_assembled')
                                        changed = check_deps(png_name, dname)
                                        changed = times.check_have_time(
                                            changed, png_name)
                                        tmp_name = 'tmp.png'
                                        if changed:
                                            print(changed)
                                            t = time.time()
                                            openscad.run(
                                                "-D$pose=1",
                                                "-D$explode=%d" % explode,
                                                colour_scheme,
                                                "--projection=p",
                                                "--imgsize=4096,4096",
                                                "--autocenter", "--viewall",
                                                "-d", dname, "-o", tmp_name,
                                                png_maker_name)
                                            times.add_time(png_name, t)
                                            do_cmd([
                                                "magick", tmp_name, "-trim",
                                                "-resize", "1004x1004",
                                                "-bordercolor", background,
                                                "-border", "10", tmp_name
                                            ])
                                            update_image(tmp_name, png_name)
                                        tn_name = png_name.replace(
                                            '.png', '_tn.png')
                                        if mtime(png_name) > mtime(tn_name):
                                            do_cmd((
                                                "magick " + png_name +
                                                " -trim -resize 280x280 -background "
                                                + background +
                                                " -gravity Center -extent 280x280 -bordercolor "
                                                + background + " -border 10 " +
                                                tmp_name).split())
                                            update_image(tmp_name, tn_name)
                                    os.remove(png_maker_name)
                                done_assemblies.append(module)
                            else:
                                if module == 'main_assembly':
                                    main_blurb = blurb.scrape_module_blurb(
                                        lines[:line_no])
                    line_no += 1
    times.print_times()
    #
    # Build the document
    #
    for print_mode in [True, False]:
        doc_name = top_dir + "readme.md"
        with open(doc_name, "wt") as doc_file:
            #
            # Title, description and picture
            #
            project = ' '.join(
                word[0].upper() + word[1:]
                for word in os.path.basename(os.getcwd()).split('_'))
            print('<a name="TOP"></a>\n# %s' % project, file=doc_file)
            main_file = bom.find_scad_file('main_assembly')
            if not main_file:
                raise Exception("can't find source for main_assembly")
            text = blurb.scrape_blurb(source_dir + '/' + main_file)
            if len(text):
                print(text, file=doc_file, end='')
            else:
                if print_mode:
                    print(Fore.MAGENTA + "Missing project description" +
                          Fore.WHITE)
            print('![Main Assembly](assemblies/%s.png)\n' %
                  flat_bom[-1]["name"].replace('_assembly', '_assembled'),
                  file=doc_file)
            eop(print_mode, doc_file, first=True)
            #
            # Build TOC
            #
            print('## Table of Contents', file=doc_file)
            print('1. [Parts list](#Parts_list)', file=doc_file)
            for ass in flat_bom:
                name = ass["name"]
                cap_name = name.replace('_', ' ').title()
                print('1. [%s](#%s)' % (cap_name, name), file=doc_file)
            print(file=doc_file)
            eop(print_mode, doc_file)
            #
            # Global BOM
            #
            print('<a name="Parts_list"></a>\n## Parts list', file=doc_file)
            types = ["vitamins", "printed", "routed"]
            headings = {
                "vitamins": "vitamins",
                "printed": "3D printed parts",
                "routed": "CNC routed parts"
            }
            things = {}
            for t in types:
                things[t] = {}
            for ass in flat_bom:
                for t in types:
                    for thing in ass[t]:
                        if thing in things[t]:
                            things[t][thing] += ass[t][thing]
                        else:
                            things[t][thing] = ass[t][thing]
            for ass in flat_bom:
                name = ass["name"][:-9].replace('_', ' ').title().replace(
                    ' ', '&nbsp;')
                print(
                    '| <span style="writing-mode: vertical-rl; text-orientation: mixed;">%s</span> '
                    % name,
                    file=doc_file,
                    end='')
            print(
                '| <span style="writing-mode: vertical-rl; text-orientation: mixed;">TOTALS</span> |  |',
                file=doc_file)

            print(('|--:' * len(flat_bom) + '|--:|:--|'), file=doc_file)

            for t in types:
                if things[t]:
                    totals = {}
                    heading = headings[t][0:1].upper() + headings[t][1:]
                    print(('|  ' * len(flat_bom) + '| | **%s** |') % heading,
                          file=doc_file)
                    for thing in sorted(things[t],
                                        key=lambda s: s.split(":")[-1]):
                        for ass in flat_bom:
                            count = ass[t][thing] if thing in ass[t] else 0
                            print('| %s ' % pad(count if count else '.', 2, 1),
                                  file=doc_file,
                                  end='')
                            name = ass["name"]
                            if name in totals:
                                totals[name] += count
                            else:
                                totals[name] = count
                        print('|  %s | %s |' % (pad(things[t][thing], 2, 1),
                                                pad(thing.split(":")[-1], 2)),
                              file=doc_file)

                    grand_total = 0
                    for ass in flat_bom:
                        name = ass["name"]
                        total = totals[name] if name in totals else 0
                        print('| %s ' % pad(total if total else '.', 2, 1),
                              file=doc_file,
                              end='')
                        grand_total += total
                    print("| %s | %s |" %
                          (pad(grand_total, 2,
                               1), pad('Total %s count' % headings[t], 2)),
                          file=doc_file)

            print(file=doc_file)
            eop(print_mode, doc_file)
            #
            # Assembly instructions
            #
            for ass in flat_bom:
                name = ass["name"]
                cap_name = name.replace('_', ' ').title()

                if ass["count"] > 1:
                    print('<a name="%s"></a>\n## %d x %s' %
                          (name, ass["count"], cap_name),
                          file=doc_file)
                else:
                    print('<a name="%s"></a>\n## %s' % (name, cap_name),
                          file=doc_file)
                vitamins = ass["vitamins"]
                if vitamins:
                    print("### Vitamins", file=doc_file)
                    print("|Qty|Description|", file=doc_file)
                    print("|--:|:----------|", file=doc_file)
                    for v in sorted(vitamins, key=lambda s: s.split(":")[-1]):
                        print("|%d|%s|" % (vitamins[v], v.split(":")[1]),
                              file=doc_file)
                    print("\n", file=doc_file)

                printed = ass["printed"]
                if printed:
                    print('### 3D Printed parts', file=doc_file)
                    keys = sorted(list(printed.keys()))
                    for i in range(len(keys)):
                        p = keys[i]
                        print('%s %d x %s |' %
                              ('\n|' if not (i % 3) else '', printed[p], p),
                              file=doc_file,
                              end='')
                        if (i % 3) == 2 or i == len(printed) - 1:
                            n = (i % 3) + 1
                            print('\n|%s' % ('--|' * n), file=doc_file)
                            for j in range(n):
                                part = keys[i - n + j + 1]
                                print('| ![%s](stls/%s) %s' %
                                      (part, part.replace('.stl', '.png'),
                                       '|\n' if j == j - 1 else ''),
                                      end='',
                                      file=doc_file)
                            print('\n', file=doc_file)
                    print('\n', file=doc_file)

                routed = ass["routed"]
                if routed:
                    print("### CNC Routed parts", file=doc_file)
                    keys = sorted(list(routed.keys()))
                    for i in range(len(keys)):
                        r = keys[i]
                        print('%s %d x %s |' %
                              ('\n|' if not (i % 3) else '', routed[r], r),
                              file=doc_file,
                              end='')
                        if (i % 3) == 2 or i == len(routed) - 1:
                            n = (i % 3) + 1
                            print('\n|%s' % ('--|' * n), file=doc_file)
                            for j in range(n):
                                part = keys[i - n + j + 1]
                                print('| ![%s](dxfs/%s) %s' %
                                      (part, part.replace('.dxf', '.png'),
                                       '|\n' if j == j - 1 else ''),
                                      end='',
                                      file=doc_file)
                            print('\n', file=doc_file)
                    print('\n', file=doc_file)

                sub_assemblies = ass["assemblies"]
                if sub_assemblies:
                    print("### Sub-assemblies", file=doc_file)
                    keys = sorted(list(sub_assemblies.keys()))
                    for i in range(len(keys)):
                        a = keys[i]
                        print('%s %d x %s |' % ('\n|' if not (i % 3) else '',
                                                sub_assemblies[a], a),
                              file=doc_file,
                              end='')
                        if (i % 3) == 2 or i == len(keys) - 1:
                            n = (i % 3) + 1
                            print('\n|%s' % ('--|' * n), file=doc_file)
                            for j in range(n):
                                a = keys[i - n + j + 1].replace(
                                    '_assembly', '_assembled')
                                print('| ![%s](assemblies/%s) %s' %
                                      (a, a + '_tn.png',
                                       '|\n' if j == j - 1 else ''),
                                      end='',
                                      file=doc_file)
                            print('\n', file=doc_file)
                    print('\n', file=doc_file)

                small = not ass["big"]
                suffix = '_tn.png' if small else '.png'
                print('### Assembly instructions', file=doc_file)
                print('![%s](assemblies/%s)\n' % (name, name + suffix),
                      file=doc_file)

                if "blurb" in ass and ass["blurb"]:
                    print(ass["blurb"], file=doc_file)
                else:
                    if print_mode:
                        print(
                            Fore.MAGENTA +
                            "Missing instructions for %s" % name, Fore.WHITE)

                name = name.replace('_assembly', '_assembled')
                print('![%s](assemblies/%s)\n' % (name, name + suffix),
                      file=doc_file)
                eop(print_mode,
                    doc_file,
                    last=ass == flat_bom[-1] and not main_blurb)
            #
            # If main module is suppressed print any blurb here
            #
            if main_blurb:
                print(main_blurb, file=doc_file)
                eop(print_mode, doc_file, last=True)
        #
        # Convert to HTML
        #
        html_name = "printme.html" if print_mode else "readme.html"
        with open(top_dir + html_name, "wt") as html_file:
            do_cmd(("python -m markdown -x tables -x sane_lists " +
                    doc_name).split(), html_file)
    #
    # Spell check
    #
    do_cmd('codespell -L od readme.md'.split())
    #
    # List the ones we didn't find
    #
    missing = set()
    for assembly in assemblies + (do_assemblies if do_assemblies else []):
        if assembly not in done_assemblies:
            missing.add(assembly)
    if missing:
        for assembly in missing:
            print(Fore.MAGENTA + "Could not find a module called", assembly,
                  Fore.WHITE)
        sys.exit(1)
Exemplo n.º 3
0
def make_parts(target, part_type, parts=None):
    #
    # Make the target directory
    #
    top_dir = set_config(target)
    target_dir = top_dir + part_type + 's'
    deps_dir = top_dir + "deps"
    if not os.path.isdir(target_dir):
        os.makedirs(target_dir)
    if not os.path.isdir(deps_dir):
        os.makedirs(deps_dir)
    times.read_times(target_dir)
    #
    # Decide which files to make
    #
    if parts:
        targets = list(
            parts)  #copy the list so we dont modify the list passed in
    else:
        targets = bom_to_parts(target_dir, part_type)
        for file in os.listdir(target_dir):
            if file.endswith('.' + part_type):
                if not file in targets:
                    print("Removing %s" % file)
                    os.remove(target_dir + '/' + file)
    #
    # Read existing STL bounds
    #
    if part_type == 'stl':
        bounds_fname = target_dir + '/bounds.json'
        try:
            with open(bounds_fname) as json_file:
                bounds_map = json.load(json_file)
        except:
            bounds_map = {}
    #
    # Find all the scad files
    #
    lib_dir = os.environ['OPENSCADPATH'] + '/NopSCADlib/printed'
    module_suffix = '_dxf' if part_type == 'svg' else '_' + part_type
    for dir in [source_dir, lib_dir]:
        for filename in os.listdir(dir):
            if filename[-5:] == ".scad":
                #
                # find any modules ending in _<part_type>
                #
                with open(dir + "/" + filename, "r") as f:
                    for line in f.readlines():
                        words = line.split()
                        if (len(words) and words[0] == "module"):
                            module = words[1].split('(')[0]
                            if module.endswith(module_suffix):
                                base_name = module[:-4]
                                part = base_name + '.' + part_type
                                if part in targets:
                                    #
                                    # make a file to use the module
                                    #
                                    part_maker_name = part_type + ".scad"
                                    with open(part_maker_name, "w") as f:
                                        f.write("use <%s/%s>\n" %
                                                (dir, filename))
                                        f.write("%s();\n" % module)
                                    #
                                    # Run openscad on the created file
                                    #
                                    part_file = target_dir + "/" + part
                                    dname = deps_name(deps_dir, filename)
                                    changed = check_deps(part_file, dname)
                                    changed = times.check_have_time(
                                        changed, part)
                                    if part_type == 'stl' and not changed and not part in bounds_map:
                                        changed = "No bounds"
                                    if changed:
                                        print(changed)
                                        t = time.time()
                                        openscad.run("-D$bom=1", "-d", dname,
                                                     "-o", part_file,
                                                     part_maker_name)
                                        times.add_time(part, t)
                                        if part_type == 'stl':
                                            bounds = c14n_stl.canonicalise(
                                                part_file)
                                            bounds_map[part] = bounds

                                    targets.remove(part)
                                    os.remove(part_maker_name)
    #
    # Write new bounds file
    #
    if part_type == 'stl':
        with open(bounds_fname, 'w') as outfile:
            json.dump(bounds_map, outfile, indent=4)
    #
    # List the ones we didn't find
    #
    if targets:
        for part in targets:
            if part[-4:] != '.' + part_type:
                print(part, "is not a", part_type, "file")
            else:
                print("Could not find a module called",
                      part[:-4] + module_suffix, "to make", part)
        sys.exit(1)
    times.print_times()
Exemplo n.º 4
0
def views(target, do_assemblies=None):
    done_assemblies = []
    #
    # Make the target directory
    #
    top_dir = set_config(target, usage)
    tmp_dir = mktmpdir(top_dir)
    target_dir = top_dir + 'assemblies'
    deps_dir = target_dir + "/deps"
    bom_dir = top_dir + "bom"
    if not os.path.isdir(target_dir):
        os.makedirs(target_dir)
    if not os.path.isdir(deps_dir):
        os.makedirs(deps_dir)

    times.read_times(target_dir)
    options.check_options(deps_dir)
    bounds_fname = top_dir + 'stls/bounds.json'
    with open(bounds_fname) as json_file:
        bounds_map = json.load(json_file)
    #
    # Find all the assemblies and remove any old views
    #
    assemblies = bom_to_assemblies(bom_dir, bounds_map)
    lc_assemblies = [ass.lower() for ass in assemblies]
    for file in os.listdir(target_dir):
        if file.endswith('.png'):
            assembly = file[:-4].replace('_assembled', '_assembly')
            if assembly.endswith('_tn'):
                assembly = assembly[:-3]
            if not assembly in assemblies:
                print("Removing %s" % file)
                os.remove(target_dir + '/' + file)
    #
    # Find all the scad files
    #
    main_blurb = None
    main_assembly, main_file = bom.main_assembly(target)
    pngs = []
    for dir in source_dirs(bom_dir):
        if os.path.isdir(dir):
            for filename in os.listdir(dir):
                if filename.endswith('.scad'):
                    #
                    # find any modules with names ending in _assembly
                    #
                    with open(dir + "/" + filename, "r") as f:
                        lines = f.readlines()
                    line_no = 0
                    for line in lines:
                        words = line.split()
                        if len(words) and words[0] == "module":
                            module = words[1].split('(')[0]
                            if is_assembly(module):
                                lc_module = module.lower()
                                if lc_module in lc_assemblies:
                                    real_name = assemblies[lc_assemblies.index(
                                        lc_module)]
                                    #
                                    # Scrape the assembly instructions
                                    #
                                    for ass in flat_bom:
                                        if ass["name"] == real_name:
                                            zoomed = ass['zoomed']
                                            if not "blurb" in ass:
                                                ass["blurb"] = blurb.scrape_module_blurb(
                                                    lines[:line_no])
                                            break

                                    #
                                    # Run openscad on the created file
                                    #
                                    dname = deps_name(deps_dir, filename)
                                    for explode in [0, 1]:
                                        #
                                        # Generate png name
                                        #
                                        png_name = target_dir + '/' + real_name + '.png'
                                        if not explode:
                                            png_name = png_name.replace(
                                                '_assembly', '_assembled')
                                        pngs.append(png_name)

                                        if not do_assemblies or real_name in do_assemblies:
                                            changed = check_deps(
                                                png_name, dname)
                                            changed = times.check_have_time(
                                                changed, png_name)
                                            changed = options.have_changed(
                                                changed, png_name)
                                            tmp_name = tmp_dir + '/' + real_name + '.png'
                                            if changed:
                                                print(changed)
                                                #
                                                # make a file to use the module
                                                #
                                                png_maker_name = tmp_dir + '/png.scad'
                                                with open(png_maker_name,
                                                          "w") as f:
                                                    f.write(
                                                        "include <NopSCADlib/global_defs.scad>\n"
                                                    )
                                                    f.write(
                                                        "use <%s/%s>\n" %
                                                        (reltmp(dir, target),
                                                         filename))
                                                    f.write("%s();\n" % module)
                                                t = time.time()
                                                target_def = [
                                                    '-D$target="%s"' % target
                                                ] if target else []
                                                cwd_def = [
                                                    '-D$cwd="%s"' %
                                                    os.getcwd().replace(
                                                        '\\', '/')
                                                ]
                                                view_def = [
                                                    '--viewall', '--autocenter'
                                                ] if not (
                                                    zoomed & (1 << explode)
                                                ) else [
                                                    '--camera=0,0,0,55,0,25,140'
                                                ]
                                                openscad.run_list(
                                                    [
                                                        "-o", tmp_name,
                                                        png_maker_name
                                                    ] + options.list() +
                                                    target_def + cwd_def +
                                                    view_def + [
                                                        "-D$pose=1",
                                                        "-D$explode=%d" %
                                                        explode, colour_scheme,
                                                        "--projection=p",
                                                        image_size, "-d", dname
                                                    ])
                                                times.add_time(png_name, t)
                                                do_cmd([
                                                    "magick", tmp_name,
                                                    "-trim", "-resize",
                                                    "1004x1004",
                                                    "-bordercolor", background,
                                                    "-border", "10", tmp_name
                                                ])
                                                update_image(
                                                    tmp_name, png_name)
                                                os.remove(png_maker_name)
                                            tn_name = png_name.replace(
                                                '.png', '_tn.png')
                                            if mtime(png_name) > mtime(
                                                    tn_name):
                                                do_cmd((
                                                    "magick " + png_name +
                                                    " -trim -resize 280x280 -background "
                                                    + background +
                                                    " -gravity Center -extent 280x280 -bordercolor "
                                                    + background +
                                                    " -border 10 " +
                                                    tmp_name).split())
                                                update_image(tmp_name, tn_name)
                                    done_assemblies.append(real_name)
                                else:
                                    if module == main_assembly:
                                        main_blurb = blurb.scrape_module_blurb(
                                            lines[:line_no])
                        line_no += 1
    #
    # Build the document
    #
    doc_name = top_dir + "readme.md"
    with open(doc_name, "wt") as doc_file:
        #
        # Title, description and picture
        #
        project = ' '.join(
            word[0].upper() + word[1:]
            for word in os.path.basename(os.getcwd()).split('_'))
        print('<a name="TOP"></a>', file=doc_file)
        print('# %s' % project, file=doc_file)
        text = blurb.scrape_blurb(source_dir + '/' + main_file)
        blurbs = blurb.split_blurb(text)
        if len(text):
            print(blurbs[0], file=doc_file)
        else:
            print(Fore.MAGENTA + "Missing project description" + Fore.WHITE)
        #
        # Only add the image if the first blurb section doesn't contain one.
        #
        if not re.search(r'\!\[.*\]\(.*\)', blurbs[0], re.MULTILINE):
            print('![Main Assembly](assemblies/%s.png)\n' %
                  flat_bom[-1]["name"].replace('_assembly', '_assembled'),
                  file=doc_file)
        eop(doc_file, first=True)
        #
        # Build TOC
        #
        print('## Table of Contents', file=doc_file)
        print('1. [Parts list](#Parts_list)', file=doc_file)
        for ass in flat_bom:
            name = ass["name"]
            cap_name = titalise(name)
            print('1. [%s](#%s)' % (cap_name, name), file=doc_file)
        print(file=doc_file)
        if len(blurbs) > 1:
            print(blurbs[1], file=doc_file)
        eop(doc_file)
        #
        # Global BOM
        #
        global_bom = [merged(ass) for ass in flat_bom if not ass['ngb']]
        print('<a name="Parts_list"></a>\n## Parts list', file=doc_file)
        headings = {
            "vitamins": "vitamins",
            "printed": "3D printed parts",
            "routed": "CNC routed parts"
        }
        things = {}
        for t in types:
            things[t] = {}
        for ass in flat_bom:
            for t in types:
                for thing in ass[t]:
                    if thing in things[t]:
                        things[t][thing] += ass[t][thing]["count"]
                    else:
                        things[t][thing] = ass[t][thing]["count"]
        for ass in global_bom:
            name = titalise(ass["name"][:-9]).replace(' ', '&nbsp;')
            if ass["count"] > 1:
                name = "%d x %s" % (ass["count"], name)
            print(
                '| <span style="writing-mode: vertical-rl; text-orientation: mixed;">%s</span> '
                % name,
                file=doc_file,
                end='')
        print(
            '| <span style="writing-mode: vertical-rl; text-orientation: mixed;">TOTALS</span> |  |',
            file=doc_file)
        print(('|---:' * len(global_bom) + '|---:|:---|'), file=doc_file)

        for t in types:
            if things[t]:
                totals = {}
                grand_total2 = 0
                heading = headings[t][0].upper() + headings[t][1:]
                print(('|  ' * len(global_bom) + '| | **%s** |') % heading,
                      file=doc_file)
                for thing in sorted(things[t], key=lambda s: s.split(":")[-1]):
                    for ass in global_bom:
                        count = ass[t][thing]["count"] if thing in ass[t] else 0
                        print('| %s ' % pad(count if count else '.', 2, 1),
                              file=doc_file,
                              end='')
                        name = ass["name"]
                        if name in totals:
                            totals[name] += count
                        else:
                            totals[name] = count
                        grand_total2 += count
                    print('|  %s | %s |' % (pad(
                        things[t][thing], 2, 1), pad(thing.split(":")[-1], 2)),
                          file=doc_file)

                grand_total = 0
                for ass in global_bom:
                    name = ass["name"]
                    total = totals[name] if name in totals else 0
                    print('| %s ' % pad(total if total else '.', 2, 1),
                          file=doc_file,
                          end='')
                    grand_total += total
                print("| %s | %s |" % (pad(grand_total, 2, 1),
                                       pad('Total %s count' % headings[t], 2)),
                      file=doc_file)
                assert grand_total == grand_total2
        print(file=doc_file)
        if len(blurbs) > 2:
            print(blurbs[2], file=doc_file)
        eop(doc_file)
        #
        # Assembly instructions
        #
        for ass in flat_bom:
            name = ass["name"]
            cap_name = titalise(name)

            print('<a name="%s"></a>' % name, file=doc_file)
            if ass["count"] > 1:
                print('## %d x %s' % (ass["count"], cap_name), file=doc_file)
            else:
                print('## %s' % cap_name, file=doc_file)
            vitamins = ass["vitamins"]
            if vitamins:
                print("### Vitamins", file=doc_file)
                print("|Qty|Description|", file=doc_file)
                print("|---:|:----------|", file=doc_file)
                for v in sorted(vitamins, key=lambda s: s.split(":")[-1]):
                    print("|%d|%s|" % (vitamins[v]["count"], v.split(":")[1]),
                          file=doc_file)
                print("\n", file=doc_file)

            printed = ass["printed"]
            if printed:
                print('### 3D Printed parts', file=doc_file)
                keys = sorted(list(printed.keys()))
                for i, p in enumerate(keys):
                    print(
                        '%s %d x %s |' %
                        ('\n|' if not (i % 3) else '', printed[p]["count"], p),
                        file=doc_file,
                        end='')
                    if (i % 3) == 2 or i == len(printed) - 1:
                        n = (i % 3) + 1
                        print('\n|%s' % ('---|' * n), file=doc_file)
                        for j in range(n):
                            part = keys[i - n + j + 1]
                            print('| ![%s](stls/%s) %s' %
                                  (part, part.replace('.stl', '.png'),
                                   '|\n' if j == j - 1 else ''),
                                  end='',
                                  file=doc_file)
                        print('\n', file=doc_file)
                print('\n', file=doc_file)

            routed = ass["routed"]
            if routed:
                print("### CNC Routed parts", file=doc_file)
                keys = sorted(list(routed.keys()))
                for i, r in enumerate(keys):
                    print(
                        '%s %d x %s |' %
                        ('\n|' if not (i % 3) else '', routed[r]["count"], r),
                        file=doc_file,
                        end='')
                    if (i % 3) == 2 or i == len(routed) - 1:
                        n = (i % 3) + 1
                        print('\n|%s' % ('---|' * n), file=doc_file)
                        for j in range(n):
                            part = keys[i - n + j + 1]
                            print('| ![%s](dxfs/%s) %s' %
                                  (part, part.replace('.dxf', '.png'),
                                   '|\n' if j == j - 1 else ''),
                                  end='',
                                  file=doc_file)
                        print('\n', file=doc_file)
                print('\n', file=doc_file)

            sub_assemblies = ass["assemblies"]
            if sub_assemblies:
                print("### Sub-assemblies", file=doc_file)
                keys = sorted(list(sub_assemblies.keys()))
                for i, a in enumerate(keys):
                    print('%s %d x %s |' %
                          ('\n|' if not (i % 3) else '', sub_assemblies[a], a),
                          file=doc_file,
                          end='')
                    if (i % 3) == 2 or i == len(keys) - 1:
                        n = (i % 3) + 1
                        print('\n|%s' % ('---|' * n), file=doc_file)
                        for j in range(n):
                            a = keys[i - n + j + 1].replace(
                                '_assembly', '_assembled')
                            print('| ![%s](assemblies/%s) %s' %
                                  (a, a + '_tn.png',
                                   '|\n' if j == j - 1 else ''),
                                  end='',
                                  file=doc_file)
                        print('\n', file=doc_file)
                print('\n', file=doc_file)

            small = not ass["big"]
            suffix = '_tn.png' if small else '.png'
            print('### Assembly instructions', file=doc_file)
            print('![%s](assemblies/%s)\n' % (name, name + suffix),
                  file=doc_file)

            if "blurb" in ass and ass["blurb"]:
                print(ass["blurb"], file=doc_file)
            else:
                print(Fore.MAGENTA + "Missing instructions for %s" % name,
                      Fore.WHITE)

            name = name.replace('_assembly', '_assembled')
            print('![%s](assemblies/%s)\n' % (name, name + suffix),
                  file=doc_file)
            eop(doc_file, last=ass == flat_bom[-1] and not main_blurb)
        #
        # If main module is suppressed print any blurb here
        #
        if main_blurb:
            print(main_blurb, file=doc_file)
            eop(doc_file, last=True)
    #
    # Convert to HTML
    #
    html_name = top_dir + 'readme.html'
    t = time.time()
    with open(html_name, "wt") as html_file:
        do_cmd(
            ("python -m markdown -x tables -x sane_lists " + doc_name).split(),
            html_file)
    times.add_time(html_name, t)
    times.print_times(pngs + [html_name])
    #
    # Make the printme.html by replacing empty spans that invisibly mark the page breaks by page break divs.
    #
    with open(html_name, 'rt') as src:
        lines = src.readlines()

    i = 0
    with open(top_dir + 'printme.html', 'wt') as dst:
        while i < len(lines):
            line = lines[i]
            if line.startswith(
                    '<p><span></span>'):  # Empty span used to mark page breaks
                i += 1
                if lines[i].startswith(
                        '<a href="#TOP">Top</a>'
                ):  # The first page break won't have one
                    i += 1
                if i < len(lines) and lines[
                        i] == '<hr />\n':  # The last page break doesn't have one
                    dst.write(
                        '<div style="page-break-after: always;"></div>\n')
                    i += 1
            else:
                dst.write(line)
                i += 1
    #
    # Remove tmp dir
    #
    rmtmpdir(tmp_dir)
    #
    # Spell check
    #
    do_cmd(('codespell -L od ' + top_dir + 'readme.md').split())
    #
    # List the ones we didn't find
    #
    missing = set()
    for assembly in assemblies + (do_assemblies if do_assemblies else []):
        if assembly not in done_assemblies:
            missing.add(assembly)
    if missing:
        for assembly in missing:
            print(Fore.MAGENTA + "Could not find a module called", assembly,
                  Fore.WHITE)
        sys.exit(1)
Exemplo n.º 5
0
def make_parts(target, part_type, parts=None):
    #
    # Check list of parts is the correct type
    #
    if parts:
        for p in parts:
            if not p.endswith('.' + part_type): usage(part_type)
    #
    # Make the target directory
    #
    top_dir = set_config(target, lambda: usage(part_type))
    target_dir = top_dir + part_type + 's'
    deps_dir = target_dir + "/deps"
    bom_dir = top_dir + "bom"
    tmp_dir = mktmpdir(top_dir)

    if not os.path.isdir(target_dir):
        os.makedirs(target_dir)

    if not os.path.isdir(deps_dir):
        os.makedirs(deps_dir)

    if os.path.isdir(top_dir + '/deps'):  #old location
        shutil.rmtree(top_dir + '/deps')

    times.read_times(target_dir)
    #
    # Decide which files to make
    #
    all_parts = bom_to_parts(bom_dir, part_type)
    if parts:
        targets = list(
            parts)  #copy the list so we dont modify the list passed in
    else:
        targets = list(all_parts)
        for file in os.listdir(target_dir):
            if file.endswith('.' + part_type):
                if not file in targets:
                    print("Removing %s" % file)
                    os.remove(target_dir + '/' + file)
    #
    # Read existing STL bounds
    #
    if part_type == 'stl':
        bounds_fname = target_dir + '/bounds.json'
        try:
            with open(bounds_fname) as json_file:
                bounds_map = json.load(json_file)
        except:
            bounds_map = {}
    #
    # Find all the scad files
    #
    module_suffix = '_dxf' if part_type == 'svg' else '_' + part_type
    for dir in source_dirs(bom_dir):
        if targets and os.path.isdir(dir):
            for filename in os.listdir(dir):
                if targets and filename[-5:] == ".scad":
                    #
                    # find any modules ending in _<part_type>
                    #
                    with open(dir + "/" + filename, "r") as f:
                        for line in f.readlines():
                            words = line.split()
                            if (len(words) and words[0] == "module"):
                                module = words[1].split('(')[0]
                                if module.endswith(module_suffix):
                                    base_name = module[:-4]
                                    part = base_name + '.' + part_type
                                    if part in targets:
                                        #
                                        # Run openscad on the created file
                                        #
                                        part_file = target_dir + "/" + part
                                        dname = deps_name(deps_dir, filename)
                                        changed = check_deps(part_file, dname)
                                        changed = times.check_have_time(
                                            changed, part)
                                        if part_type == 'stl' and not changed and not part in bounds_map:
                                            changed = "No bounds"
                                        if changed:
                                            print(changed)
                                            #
                                            # make a file to use the module
                                            #
                                            part_maker_name = tmp_dir + '/' + part_type + ".scad"
                                            with open(part_maker_name,
                                                      "w") as f:
                                                f.write("use <%s/%s>\n" %
                                                        (reltmp(dir, target),
                                                         filename))
                                                f.write("%s();\n" % module)
                                            t = time.time()
                                            openscad.run(
                                                "-D$bom=1", "-d", dname, "-o",
                                                part_file, part_maker_name)
                                            times.add_time(part, t)
                                            if part_type == 'stl':
                                                bounds = c14n_stl.canonicalise(
                                                    part_file)
                                                bounds_map[part] = bounds
                                            os.remove(part_maker_name)
                                        targets.remove(part)
    #
    # Write new bounds file
    #
    if part_type == 'stl':
        with open(bounds_fname, 'w') as outfile:
            json.dump(bounds_map, outfile, indent=4)
    #
    # Remove tmp dir
    #
    rmtmpdir(tmp_dir)
    #
    # List the ones we didn't find
    #
    if targets:
        for part in targets:
            print("Could not find a module called", part[:-4] + module_suffix,
                  "to make", part)
        usage(part_type)
    times.print_times(all_parts)
Exemplo n.º 6
0
def tests(tests):
    scad_dir = "tests"
    deps_dir = scad_dir + "/deps"
    png_dir = scad_dir + "/png"
    bom_dir = scad_dir + "/bom"
    for dir in [deps_dir, png_dir, bom_dir]:
        if not os.path.isdir(dir):
            os.makedirs(dir)
    index = {}
    bodies = {}
    done = []
    times.read_times()
    options.check_options(deps_dir)
    #
    # Make cover pic if does not exist as very slow. Delete it to force an update.
    #
    png_name = "libtest.png"
    scad_name = "libtest.scad"
    if os.path.isfile(scad_name):
        libtest = True
        lib_blurb = scrape_blurb(scad_name)
        if not os.path.isfile(png_name):
            openscad.run(colour_scheme, "--projection=p",
                         "--imgsize=%d,%d" % (w, h),
                         "--camera=0,0,0,50,0,340,500", "--autocenter",
                         "--viewall", "-o", png_name, scad_name)
            do_cmd([
                "magick", png_name, "-trim", "-resize", "1280", "-bordercolor",
                background, "-border", "10", png_name
            ])
    else:
        #
        # Project tests so just a title
        #
        libtest = False
        project = ' '.join(
            word[0].upper() + word[1:]
            for word in os.path.basename(os.getcwd()).split('_'))
        lib_blurb = '#' + project + ' Tests\n'

    doc_base_name = "readme" if libtest else "tests"
    doc_name = doc_base_name + ".md"
    #
    # List of individual part files
    #

    scads = [
        i for i in sorted(os.listdir(scad_dir), key=lambda s: s.lower())
        if i[-5:] == ".scad"
    ]
    types = []
    for scad in scads:
        base_name = scad[:-5]
        if not tests or base_name in tests:
            done.append(base_name)
            print('\n' + base_name)
            cap_name = base_name[0].capitalize() + base_name[1:]
            base_name = base_name.lower()
            scad_name = scad_dir + '/' + scad
            png_name = png_dir + '/' + base_name + '.png'
            bom_name = bom_dir + '/' + base_name + '.json'

            objects_name = None
            vits_name = 'vitamins/' + base_name + '.scad'
            if is_plural(base_name) and os.path.isfile(vits_name):
                objects_name = vits_name

            locations = []
            if os.path.isdir('vitamins'):
                locations.append(
                    ('vitamins/' + depluralise(base_name) + '.scad',
                     'Vitamins'))
            if os.path.isdir('printed'):
                locations.append(('printed/' + base_name + '.scad', 'Printed'))
            if os.path.isdir('utils'):
                locations.append(('utils/' + base_name + '.scad', 'Utilities'))
            if libtest and os.path.isdir('utils/core'):
                locations.append(
                    ('utils/core/' + base_name + '.scad', 'Core Utilities'))

            for name, type in locations:
                if os.path.isfile(name):
                    impl_name = name
                    break
            else:
                if libtest:
                    print("Can't find implementation!")
                    continue
                else:
                    type = 'Tests'  # OK when testing part of a project
                    impl_name = None

            if libtest:
                vsplit = "AJR" + chr(ord('Z') + 1)
                vtype = locations[0][1]
                types = [
                    vtype + ' ' + vsplit[i] + '-' +
                    chr(ord(vsplit[i + 1]) - 1)
                    for i in range(len(vsplit) - 1)
                ] + [loc[1] for loc in locations[1:]]
                if type == vtype:
                    for i in range(1, len(vsplit)):
                        if cap_name[0] < vsplit[i]:
                            type = types[i - 1]
                            break
            else:
                if not types:
                    types = [loc[1] for loc in locations
                             ]  # No need to split up the vitamin list
                    if not type in types:  # Will happen when implementation is not found and type is set to Tests
                        types.append(type)

            for t in types:
                if not t in bodies:
                    bodies[t] = []
                    index[t] = []

            body = bodies[type]

            index[type] += [cap_name]
            body += ['<a name="%s"></a>' % cap_name]
            body += ["## " + cap_name]

            doc = None
            if impl_name:
                doc = scrape_code(impl_name)
                blurb = doc["blurb"]
            else:
                blurb = scrape_blurb(scad_name)

            if not len(blurb):
                print("Blurb not found!")
            else:
                body += [blurb]

            if objects_name:
                body += [
                    "[%s](%s) Object definitions.\n" %
                    (objects_name, objects_name)
                ]

            if impl_name:
                body += ["[%s](%s) Implementation.\n" % (impl_name, impl_name)]

            body += [
                "[%s](%s) Code for this example.\n" %
                (scad_name.replace('\\', '/'), scad_name)
            ]

            if doc:
                for thing, heading in [("properties", "Function"),
                                       ("functions", "Function"),
                                       ("modules", "Module")]:
                    things = doc[thing]
                    if things:
                        body += [
                            '### %s\n| %s | Description |\n|:--- |:--- |' %
                            (thing.title(), heading)
                        ]
                        for item in sorted(things):
                            body += ['| `%s` | %s |' % (item, things[item])]
                        body += ['']

            body += ["![%s](%s)\n" % (base_name, png_name)]

            dname = deps_name(deps_dir, scad.lower())
            oldest = png_name if mtime(png_name) < mtime(
                bom_name) else bom_name
            changed = check_deps(oldest, dname)
            changed = times.check_have_time(changed, scad_name)
            changed = options.have_changed(changed, oldest)
            if changed:
                print(changed)
                t = time.time()
                tmp_name = 'tmp.png'
                openscad.run_list(options.list() + [
                    "-D$bom=2", colour_scheme, "--projection=p",
                    "--imgsize=%d,%d" %
                    (w, h), "--camera=0,0,0,70,0,315,500", "--autocenter",
                    "--viewall", "-d", dname, "-o", tmp_name, scad_name
                ])
                times.add_time(scad_name, t)
                do_cmd([
                    "magick", tmp_name, "-trim", "-resize", "1000x600",
                    "-bordercolor", background, "-border", "10", tmp_name
                ])
                update_image(tmp_name, png_name)
                BOM = bom.parse_bom()
                with open(bom_name, 'wt') as outfile:
                    json.dump(BOM.flat_data(), outfile, indent=4)

            with open(bom_name, "rt") as bom_file:
                BOM = json.load(bom_file)
                for thing, heading in [("vitamins", "Module call | BOM entry"),
                                       ("printed", "Filename"),
                                       ("routed", "Filename"),
                                       ("assemblies", "Name")]:
                    things = BOM[thing]
                    if things:
                        body += [
                            '### %s\n| Qty | %s |\n| ---:|:--- |%s' %
                            (thing.title(), heading,
                             ':---|' if '|' in heading else '')
                        ]
                        for item in sorted(things,
                                           key=lambda s: s.split(":")[-1]):
                            name = item
                            desc = ''
                            if thing == "vitamins":
                                vit = item.split(':')
                                name = '`' + vit[0] + '`' if vit[0] else ''
                                while '[[' in name and ']]' in name:
                                    i = name.find('[[')
                                    j = name.find(']]') + 2
                                    name = name.replace(name[i:j], '[ ... ]')
                                desc = vit[1]
                                body += [
                                    '| %3d | %s | %s |' %
                                    (things[item]["count"], name, desc)
                                ]
                            else:
                                count = things[
                                    item] if thing == 'assemblies' else things[
                                        item]["count"]
                                body += ['| %3d | %s |' % (count, name)]
                        body += ['']

            body += ['\n<a href="#top">Top</a>']
            body += ["\n---"]

    for test in done:
        if test in tests:
            tests.remove(test)
    if tests:
        for test in tests:
            print(Fore.MAGENTA + "Could not find a test called", test,
                  Fore.WHITE)
        usage()

    with open(doc_name, "wt") as doc_file:
        print(lib_blurb, file=doc_file)
        print('## Table of Contents<a name="top"/>', file=doc_file)
        print('<table><tr>', file=doc_file)
        n = 0
        for type in types:
            print('<th align="left"> %s </th>' % type, end='', file=doc_file)
            n = max(n, len(index[type]))
        print('</tr>', file=doc_file)
        for i in range(n):
            print('<tr>', file=doc_file, end='')
            for type in types:
                if i < len(index[type]):
                    name = sorted(index[type])[i]
                    print('<td> <a href = "#' + name + '">' + name +
                          '</a> </td>',
                          file=doc_file,
                          end='')
                else:
                    print('<td></td>', file=doc_file, end='')
            print('</tr>', file=doc_file)
        print('</table>\n\n---', file=doc_file)
        for type in types:
            for line in bodies[type]:
                print(line, file=doc_file)
    with open(doc_base_name + ".html", "wt") as html_file:
        do_cmd(("python -m markdown -x tables " + doc_name).split(), html_file)
    times.print_times()
    do_cmd(('codespell -L od ' + doc_name).split())
Exemplo n.º 7
0
def plateup(target, part_type, usage = None):
    #
    # Make the target directory
    #
    top_dir = set_config(target, usage)
    parts_dir = top_dir + part_type + 's'
    target_dir = parts_dir + '/' + target_dirs[part_type]
    source_dir1 = source_dirs[part_type]
    source_dir2 = top_dir + source_dirs[part_type]

    #
    # Loop through source directories
    #
    all_used = []
    all_sources = []
    all_parts = []
    read_times = False
    for dir in [source_dir1, source_dir2]:
        if not os.path.isdir(dir):
            continue
        if not os.path.isdir(target_dir):
            os.makedirs(target_dir)

        if not read_times:
            times.read_times(target_dir)
            read_times = True
        #
        # Make the deps dir
        #
        deps_dir = parts_dir + "/deps"
        if not os.path.isdir(deps_dir):
            os.makedirs(deps_dir)

        if os.path.isdir(dir + '/deps'): #old deps
            shutil.rmtree(dir + '/deps')
        #
        # Decide which files to make
        #
        sources = [file for file in os.listdir(dir) if file.endswith('.scad')]
        all_sources += sources
        #
        # Run OpenSCAD on the source files to make the targets
        #
        target_def = ['-D$target="%s"' % target] if target else []
        cwd_def = ['-D$cwd="%s"' % os.getcwd().replace('\\', '/')]
        for src in sources:
            src_file = dir + '/' + src
            part =  src[:-4] + part_type
            all_parts.append(part)
            part_file = target_dir + '/' + part
            uses_file = deps_dir + '/' + src[:-4] + 'txt'
            dname = deps_name(deps_dir, src)
            oldest = part_file if mtime(part_file) < mtime(uses_file) else uses_file
            changed = check_deps(oldest, dname)
            used = []
            if changed:
                print(changed)
                t = time.time()
                openscad.run_list(["-D$bom=1"] + target_def + cwd_def + ["-d", dname, "-o", part_file, src_file])
                if part_type == 'stl':
                    c14n_stl.canonicalise(part_file)
                times.add_time(part, t)
                log_name = 'openscad.log'
                #
                # Add the files on the BOM to the used list
                #
                with open(log_name) as file:
                    for line in file.readlines():
                        match = re.match(r'^ECHO: "~(.*?\.' + part_type + r').*"$', line)
                        if match:
                            used.append(match.group(1))
                with open(uses_file, "wt") as file:
                    for part in used:
                        print(part, file = file)
            else:
                with open(uses_file, "rt") as file:
                    for line in file:
                        used.append(line[:-1])
            all_used += used

    copied = []
    if all_sources:
        #
        # Copy files that are not included
        #
        for file in os.listdir(parts_dir):
            if file.endswith('.' + part_type) and not file in all_used:
                src = parts_dir + '/' + file
                dst = target_dir + '/' + file
                if mtime(src) > mtime(dst):
                    print("Copying %s to %s" % (src, dst))
                    shutil.copyfile(src, dst)
                copied.append(file)
        #
        # Remove any cruft
        #
        targets = [file[:-4] + part_type for file in all_sources]
        for file in os.listdir(target_dir):
            if file.endswith('.' + part_type):
                if not file in targets and not file in copied:
                    print("Removing %s" % file)
                    os.remove(target_dir + '/' + file)

        targets = [file[:-4] + 'txt' for file in all_sources]
        for file in os.listdir(deps_dir):
            if file.endswith('.' + 'txt'):
                if not file in targets:
                    print("Removing %s" % file)
                    os.remove(deps_dir + '/' + file)

        times.print_times(all_parts)