feat: add support for a --noBackup flag and UI checkbox & dev containers (#221)

* Add vscode devcontainer

* Add test files to gitignore

* Add --noBackup flag

* Update installer
This commit is contained in:
Neil Enns
2025-10-12 23:18:09 -07:00
committed by GitHub
parent 3381050309
commit a20484abc5
8 changed files with 63 additions and 13 deletions
+17
View File
@@ -0,0 +1,17 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/python
{
"name": "Python 3",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/python:1": {},
"ghcr.io/stuartleeks/dev-container-features/shell-history:0": {},
"ghcr.io/neilenns/devcontainer-features/oh-my-zsh": {
"disableAutoUpdate": false,
"disableUpdatePrompt": false,
"stripWorkspacesFromPrompt": true,
"theme": "agnoster"
}
},
"postCreateCommand": ".devcontainer/install-kicad.sh"
}
+22
View File
@@ -0,0 +1,22 @@
#!/bin/bash
set -e
echo "Installing prerequisites..."
sudo apt update > /dev/null 2>&1 && sudo apt install -y software-properties-common > /dev/null 2>&1
echo "Installing KiCad (takes a few minutes)..."
sudo add-apt-repository -y ppa:kicad/kicad-9.0-releases > /dev/null 2>&1
sudo apt update > /dev/null 2>&1
sudo apt install -y --no-install-recommends kicad kicad-symbols kicad-footprints > /dev/null 2>&1
# Link KiCad plugin to workspace path
echo "Linking KiCad plugin..."
mkdir -p "$HOME/.local/share/kicad/9.0/3rdparty/plugins"
ln -s /workspaces/Fabrication-Toolkit/plugins "$HOME/.local/share/kicad/9.0/3rdparty/plugins/com_github_bennymeg_JLC-Plugin-for-KiCad"
mkdir -p "$HOME/.local/share/kicad/9.0/3rdparty/resources"
ln -s /workspaces/Fabrication-Toolkit/resources "$HOME/.local/share/kicad/9.0/3rdparty/resources/com_github_bennymeg_JLC-Plugin-for-KiCad"
# Add plugin to PYTHONPATH
echo "Adding plugin to PYTHONPATH..."
echo 'export PYTHONPATH="$PYTHONPATH:$HOME/.local/share/kicad/9.0/3rdparty/plugins"' >> "$HOME/.zshrc"
+2 -1
View File
@@ -1,4 +1,5 @@
.venv
dist/
.DS_Store
*.pyc
*.pyc
Test/
+2 -1
View File
@@ -190,7 +190,7 @@ python3 -m plugins.cli -h
usage: Fabrication Toolkit [-h] --path PATH [--additionalLayers LAYERS] [--user1VCut] [--user2AltVCut]
[--autoTranslate] [--autoFill] [--excludeDNP] [--allActiveLayers] [--archiveName NAME]
[--openBrowser]
[--openBrowser] [--noBackup]
Generates JLCPCB production files from a KiCAD board file
@@ -209,6 +209,7 @@ options:
--archiveName NAME, -aN NAME
Name of the generated archives
--openBrowser, -b Open web browser with directory file overview after generation
--noBackup, -nB Do not create a backup of the project before generation
```
+3 -1
View File
@@ -19,6 +19,7 @@ if __name__ == '__main__':
parser.add_argument("--archiveName", "-aN", type=str, help="Name of the generated archives", metavar="NAME")
parser.add_argument("--openBrowser", "-b", action="store_true", help="Open webbrowser with directory file overview after generation")
parser.add_argument("--nonInteractive", "-nI" ,action="store_true", help="Run in non-Interactive mode. Usefull in CI/CD enviroment.")
parser.add_argument("--noBackup", "-nB", action="store_true", help="Do not create backup files")
args = parser.parse_args()
options = dict()
@@ -30,7 +31,8 @@ if __name__ == '__main__':
options[ALL_ACTIVE_LAYERS_OPT] = args.allActiveLayers
options[ARCHIVE_NAME] = args.archiveName
options[EXTRA_LAYERS] = args.additionalLayers
options[NO_BACKUP] = args.no_backup
openBrowser = args.openBrowser
nonInteractive = args.nonInteractive
+2 -1
View File
@@ -7,4 +7,5 @@ ALTERNATIVE_EDGE_CUT_OPT = "ALTERNATIVE_EDGE_CUT"
ALL_ACTIVE_LAYERS_OPT = "ALL_ACTIVE_LAYERS"
OPEN_BROWSER_OPT = "OPEN BROWSER"
ARCHIVE_NAME = "ARCHIVE_NAME"
EXTRA_LAYERS = "EXTRA_LAYERS"
EXTRA_LAYERS = "EXTRA_LAYERS"
NO_BACKUP = "NO_BACKUP"
+10 -5
View File
@@ -1,10 +1,10 @@
import os
import wx
import pcbnew # type: ignore
import pcbnew # type: ignore
from .thread import ProcessThread
from .events import StatusEvent
from .options import AUTO_FILL_OPT, AUTO_TRANSLATE_OPT, EXCLUDE_DNP_OPT, EXTEND_EDGE_CUT_OPT, ALTERNATIVE_EDGE_CUT_OPT, EXTRA_LAYERS, ALL_ACTIVE_LAYERS_OPT, ARCHIVE_NAME, OPEN_BROWSER_OPT
from .options import AUTO_FILL_OPT, AUTO_TRANSLATE_OPT, EXCLUDE_DNP_OPT, EXTEND_EDGE_CUT_OPT, ALTERNATIVE_EDGE_CUT_OPT, EXTRA_LAYERS, ALL_ACTIVE_LAYERS_OPT, ARCHIVE_NAME, OPEN_BROWSER_OPT, NO_BACKUP
from .utils import load_user_options, save_user_options, get_layer_names
@@ -19,7 +19,7 @@ class KiCadToJLCForm(wx.Frame):
pos=wx.DefaultPosition,
size=wx.DefaultSize,
style=wx.DEFAULT_DIALOG_STYLE)
# self.app = wx.PySimpleApp()
icon = wx.Icon(os.path.join(os.path.dirname(__file__), 'icon.png'))
self.SetIcon(icon)
@@ -36,7 +36,8 @@ class KiCadToJLCForm(wx.Frame):
AUTO_TRANSLATE_OPT: True,
AUTO_FILL_OPT: True,
EXCLUDE_DNP_OPT: False,
OPEN_BROWSER_OPT: True
OPEN_BROWSER_OPT: True,
NO_BACKUP: False,
})
self.mOptionsLabel = wx.StaticText(self, label='Options:')
@@ -66,6 +67,8 @@ class KiCadToJLCForm(wx.Frame):
self.mExcludeDnpCheckbox.SetValue(userOptions[EXCLUDE_DNP_OPT])
self.mOpenBrowserCheckbox = wx.CheckBox(self, label='Open browser after generation')
self.mOpenBrowserCheckbox.SetValue(userOptions[OPEN_BROWSER_OPT])
self.mNoBackupCheckbox = wx.CheckBox(self, label='Do not create backup files')
self.mNoBackupCheckbox.SetValue(userOptions[NO_BACKUP])
self.mGaugeStatus = wx.Gauge(
self, wx.ID_ANY, 100, wx.DefaultPosition, wx.Size(600, 20), wx.GA_HORIZONTAL)
@@ -88,6 +91,7 @@ class KiCadToJLCForm(wx.Frame):
boxSizer.Add(self.mAutomaticFillCheckbox, 0, wx.ALL, 5)
boxSizer.Add(self.mExcludeDnpCheckbox, 0, wx.ALL, 5)
boxSizer.Add(self.mOpenBrowserCheckbox, 0, wx.ALL, 5)
boxSizer.Add(self.mNoBackupCheckbox, 0, wx.ALL, 5)
boxSizer.Add(self.mGaugeStatus, 0, wx.ALL, 5)
boxSizer.Add(self.mGenerateButton, 0, wx.ALL, 5)
@@ -107,7 +111,6 @@ class KiCadToJLCForm(wx.Frame):
else:
event.Skip()
def onGenerateButtonClick(self, event):
options = dict()
options[ARCHIVE_NAME] = self.mArchiveNameControl.GetValue()
@@ -119,6 +122,7 @@ class KiCadToJLCForm(wx.Frame):
options[AUTO_FILL_OPT] = self.mAutomaticFillCheckbox.GetValue()
options[EXCLUDE_DNP_OPT] = self.mExcludeDnpCheckbox.GetValue()
options[OPEN_BROWSER_OPT] = self.mOpenBrowserCheckbox.GetValue()
options[NO_BACKUP] = self.mNoBackupCheckbox.GetValue()
save_user_options(options)
@@ -131,6 +135,7 @@ class KiCadToJLCForm(wx.Frame):
self.mAutomaticTranslationCheckbox.Hide()
self.mAutomaticFillCheckbox.Hide()
self.mExcludeDnpCheckbox.Hide()
self.mOpenBrowserCheckbox.Hide()
self.mGenerateButton.Hide()
self.mGaugeStatus.Show()
+5 -4
View File
@@ -166,10 +166,11 @@ class ProcessThread(Thread):
os.rename(os.path.join(temp_dir, placementFileName), os.path.join(temp_dir, ProcessManager.normalize_filename("_".join((baseName.strip() + '_positions.csv').split()))))
os.rename(os.path.join(temp_dir, bomFileName), os.path.join(temp_dir, ProcessManager.normalize_filename("_".join((baseName.strip() + '_bom.csv').split()))))
timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S')
backup_name = ProcessManager.normalize_filename("_".join(("{} {}".format(baseName, timestamp).strip()).split()))
shutil.make_archive(os.path.join(output_path, 'backups', backup_name), 'zip', temp_dir)
# Make a backup as long as the NO_BACKUP flag isn't set.
if not self.options[NO_BACKUP]:
timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S')
backup_name = ProcessManager.normalize_filename("_".join(("{} {}".format(baseName, timestamp).strip()).split()))
shutil.make_archive(os.path.join(output_path, 'backups', backup_name), 'zip', temp_dir)
# copy to & open output dir
try: