Skip to content

Commit

Permalink
Merge from ScopeFoundry:master
Browse files Browse the repository at this point in the history
commit 'bc788dbf926709f3c496ddcd2355d6b60d6d3c23'

# Conflicts:
#	ScopeFoundry/measurement.py
  • Loading branch information
edbarnard committed Mar 29, 2023
2 parents 016961a + bc788db commit fe8895e
Show file tree
Hide file tree
Showing 29 changed files with 1,651 additions and 0 deletions.
Empty file added plugin_manager/__init__.py
Empty file.
Binary file added plugin_manager/docs/create_new_hw.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
187 changes: 187 additions & 0 deletions plugin_manager/docs/descriptions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# Features



## import from GitHub

```
origin_repo = https://github.com/ScopeFoundry/HW_random_gen.git
my GitHub = UBene
```

produces repos:

```mermaid
flowchart TD
ScopeFoundryProject(ScopeFoundry:HW_random_gen)
style ScopeFoundryProject fill:orange
id2[UBene:HW_random_gen]
Megascope[MegaScope]
style Megascope fill:lightgreen;
subgraph Github
ScopeFoundryProject -->|1. fork|id2
end
id2 -->|2. subtree merge \n ScopeFoundryHW\random_gen|Megascope
```

Works without step 1. fork works as well. But I think there need to a GitHub repos for later pull requests.

Alternative.

1. No git usage. Direct download and import to ScopeFoundryHW\
2. Using submodules:
1. drawback Mega scope does not track new module. (can update it)

## create new Hardware

![image-20230208231723807](C:\Users\bened\eclipse-workspace\scope_foundry_dev\ScopeFoundryPlugInManager\docs\create_new_hw.png)

Generates a hardware module from templates.

###### Benefits:

- a standardized way of creating HW components. The template indicate some best practices.

###### Progress

- [x] implemented
- [ ] Does run?
- [ ] Check typos and best practices
- [ ] Analog for new Microscope:
- [ ] Questions: Should this include the random_gen HW?



## subtree push HW


###### Repos

```mermaid
flowchart TD
ScopeFoundryProject(ScopeFoundry:HW_company_model)
style ScopeFoundryProject fill:orange
id3[ScopeFoundry\plugin_manager\my_repos\HW_company_model.git]
id31[ScopeFoundry\plugin_manager\my_repos\HW_company_model]
id2[UBene:HW_company_model]
Megascope[MegaScope]
style Megascope fill:lightgreen;
Megascope -->|1. subtree push ScopeFoundryHW\company_model|id3
id3 -->|2A clone| id31
id31 -->|2B clone| id2
subgraph Github
ScopeFoundryProject <-.->|3. request fork clone or push| id2
end
```
###### Progress

- [ ] implemented
- [x] initial subtree push
- [ ] do we need step `2A clone`? Not sure
- [ ] push after new commits
- [ ] pull (from down stream)
- [ ] tests
- [ ] for HW created by users
- [ ] for imported modules or should this be handled separately?
- [ ] Rewarding for sharing a HW: Promise authorship on ScopeFoundry project if they write you an email and you accept changes?


## Dealing with other modules.

What are other modules like

```
MegaScope.sequencer
MegaScope.confocal_measure
MegaScope.nikon_microscope
etc ...
```

Idea **subtree push analog to HW** thereby creating repos:

```
SFM_Sequencer
SFM_confocal
SFM_nikon_microscope
```


## Thoughts on defining complete MegaScopes:

#### Modular strategy:

1. D3: publish all modules required for a microscope and generate a sharable file

1. option heavy: loops through all ScopeFoundryHW invoke B2 and all SFM and invokes C1 within a MegaScope project
2. option light: tries to only publish modules required for a microscope.

Either way the sharable file is a list containing SFM and HW modules and their github repos. There could be a freezing option by also including a git commit id.

2. D4: Read in sharable files and pull all modules.

###### Benefit and drawback

- highly modular
- harder to implement

#### Publish all on GitHub

Example

```
odmr_scope
- ScopeFoundry
- ScopeFoundryHW
- pulse_blaster
- ni_daq_gated_counters
- ...
- odmr_measurements
- views
rabi.py
esr.py
data_browser_app.py
...
- app.py
```



###### Benefit and drawback:

- simple!
- no modularity.


###### Progress

None

- [ ] name scheme
- [ ] implementation analog to handling HW
- [ ] feasibility

### Dependencies


```
- GitHub Account
- Terminal that:
- git
- git-cli (handy but can be removed)
- bash (not sure if bash.exe installs globally with the terminal that comes with git)
```

###### Progress

- [ ] Step by step instruction needed?

Binary file added plugin_manager/docs/image-20230208231411849.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
106 changes: 106 additions & 0 deletions plugin_manager/features/import_from_gh_controller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from .import_from_gh_qt_view import ImportFromGhView as View
from .utils import InfoTypes, decorate_info_text, run_subprocess


class ImportFromGhController:
def __init__(self, view: View):
self.view = view
# self.view.validate_my_gh_acc_validate_clicked(self.validate_my_gh_acc)
self.view.validate_origin_repo_clicked(self.validate_origin_repo)
self.view.fork_clicked(self.fork_on_gh)
self.view.import_clicked(self.import_from_origin)
self.view.validate_fork_clicked(self.validate_fork)
self.view.import_from_fork_clicked(self.import_from_fork)

self.view.set_ready_to_import(False)
self.view.set_ready_to_import_from_fork(False)

def set_msg(self, text, info_type=InfoTypes.INFO):
text = decorate_info_text(text, info_type)
self.view.set_info_text(text)

def append_msg(self, text, info_type=InfoTypes.INFO):
text = decorate_info_text(text, info_type)
self.view.append_info(text)

def new_task_msg(self, text):
self.set_msg(text, InfoTypes.TASK)

def validate_my_gh_acc(self):
raise NotImplementedError
# no necessary
# self.set_info('validating my acc')
# self.view.set_my_gh_acc_valid(True)

def validate_origin_repo(self):
origin_repo = self.view.get_origin_repo()
self.new_task_msg(f'validating origin repo {origin_repo}')
success = self.check_exists_and_report(origin_repo)
# self.view.set_origin_repo_valid(success)
self.view.set_ready_to_import(success)

def import_from_origin(self):
origin_repo = self.view.get_origin_repo()
name = origin_repo.split('/')[-1].strip('.git').strip('HW_')
destination_dir = f"ScopeFoundryHW/{name}"
self.import_repo(origin_repo, destination_dir)

def fork_on_gh(self):
origin_repo = self.view.get_origin_repo()

stdout, stderr = fork_on_gh(origin_repo)
self.append_msg(stdout, InfoTypes.INFO)
self.append_msg(stderr, InfoTypes.ERROR)
self.validate_fork()

def import_from_fork(self):
origin_repo = self.view.get_origin_repo()
name = origin_repo.split('/')[-1].strip('.git').strip('HW_')
my_gh_acc = self.view.get_my_gh_acc()

repo_to_import = f"https://github.com/{my_gh_acc}/HW_{name}.git"
destination_dir = f"ScopeFoundryHW/{name}"
self.new_task_msg(f'importing {repo_to_import} to {destination_dir}')
self.import_repo(repo_to_import, destination_dir)

def validate_fork(self):
my_gh_acc = self.view.get_my_gh_acc()
origin_repo = self.view.get_origin_repo()
module_name = origin_repo.split('/')[-1].strip('.git')

forked_repo = f"https://github.com/{my_gh_acc}/{module_name}"
self.new_task_msg(f'validating fork repo {forked_repo}')
success = self.check_exists_and_report(forked_repo)
self.view.set_ready_to_import_from_fork(success)

def import_repo(self, repo_to_import, destination_dir):
remote_name = repo_to_import.split('/')[-1].strip('.git')
stdout, stderr = subtree_merge_strategy(
remote_name, repo_to_import, destination_dir)
self.append_msg(stdout, InfoTypes.INFO)
self.append_msg(stderr, InfoTypes.ERROR)

def check_exists_and_report(self, repo):
stdout, stderr = ls_repo(repo)
exists = stderr == ""
if exists:
self.append_msg(f"repo exists: {repo}", InfoTypes.SUCCESS)
else:
self.append_msg(f"repo does NOT exist {repo}", InfoTypes.FAILED)
# self.append_info(stdout, InfoTypes.INFO)
self.append_msg(stderr, InfoTypes.ERROR)
return exists


def fork_on_gh(origin_repo):
return run_subprocess(f"gh repo fork {origin_repo} --remote=True")


def ls_repo(repo="https://github.com/ScopeFoundry/HW_picam.git"):
cmd = f"git ls-remote {repo}"
return run_subprocess(cmd)


def subtree_merge_strategy(remote_name, repo_to_import, destination_dir):
cmd = f"bash scripts/merge_remote_tree_with_subdir.sh {remote_name} {repo_to_import} {destination_dir}"
return run_subprocess(cmd)
95 changes: 95 additions & 0 deletions plugin_manager/features/import_from_gh_qt_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from qtpy.QtWidgets import (QCheckBox, QComboBox, QGroupBox, QHBoxLayout,
QLabel, QLineEdit, QPushButton, QTextEdit,
QVBoxLayout)


class ImportFromGhView(QGroupBox):

def __init__(self) -> None:
super().__init__()
self.setup()

def setup(self) -> None:
layout = QVBoxLayout()
self.setLayout(layout)

self.origin_repo_label = QLabel('origin repo')
self.origin_repo_le = QLineEdit(
'https://github.com/ScopeFoundry/HW_acton_spec.git')
self.origin_repo_validat_btn = QPushButton('validate')
self.origin_repo_validat_btn.setMaximumWidth(55)
self.import_btn = QPushButton('Import from origin')
self.import_btn.setEnabled(False)
origin_layout = QHBoxLayout()
origin_layout.addWidget(self.origin_repo_label)
origin_layout.addWidget(self.origin_repo_le)
origin_layout.addWidget(self.origin_repo_validat_btn)
origin_layout.addWidget(self.import_btn)
layout.addLayout(origin_layout)

self.my_gh_acc_label = QLabel('my GitHub')
self.my_gh_acc_le = QLineEdit('UBene')
self.my_gh_acc_validate_btn = QPushButton('validate')
self.my_gh_acc_validate_btn.setMaximumWidth(55)
self.my_gh_acc_is_valid_cb = QCheckBox('')
self.my_gh_acc_is_valid_cb.setEnabled(False)
self.my_gh_acc_is_valid_cb.setMaximumWidth(15)
self.fork_btn = QPushButton('Fork to my gh')
self.validate_fork_btn = QPushButton('validate fork')
self.import_from_fork_btn = QPushButton('import from fork')
self.import_from_fork_btn.setEnabled(False)
fork_layout = QHBoxLayout()
fork_layout.addWidget(self.my_gh_acc_label)
fork_layout.addWidget(self.my_gh_acc_le)
fork_layout.addWidget(self.fork_btn)
fork_layout.addWidget(self.validate_fork_btn)
fork_layout.addWidget(self.import_from_fork_btn)
layout.addLayout(fork_layout)

self.info_box = QTextEdit('')
layout.addWidget(self.info_box)

def validate_origin_repo_clicked(self, callback):
self.origin_repo_validat_btn.clicked.connect(callback)

def validate_my_gh_acc_validate_clicked(self, callback):
self.my_gh_acc_validate_btn.clicked.connect(callback)

def fork_clicked(self, callback):
self.fork_btn.clicked.connect(callback)

def validate_fork_clicked(self, callback):
self.validate_fork_btn.clicked.connect(callback)

def import_from_fork_clicked(self, callback):
self.import_from_fork_btn.clicked.connect(callback)

def set_ready_to_import_from_fork(self, ready):
self.import_from_fork_btn.setEnabled(ready)

def import_clicked(self, callback):
self.import_btn.clicked.connect(callback)

def set_ready_to_import(self, ready):
self.import_btn.setEnabled(ready)

def set_my_gh_acc_valid(self, checked):
self.my_gh_acc_is_valid_cb.setChecked(checked)

def get_origin_repo(self) -> str:
return self.origin_repo_le.text()

def set_origin_repo(self, text):
self.origin_repo_le.setText(text)

def get_my_gh_acc(self) -> str:
return self.my_gh_acc_le.text()

def set_my_gh_acc(self, text):
self.my_gh_acc_le.setText(text)

def set_info_text(self, text):
self.info_box.setHtml(text)

def append_info(self, text):
self.info_box.setHtml(self.info_box.toHtml() + text)

0 comments on commit fe8895e

Please sign in to comment.