mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Merge branch 'develop' into develop-2.9
This commit is contained in:
8
.github/stale.yml
vendored
8
.github/stale.yml
vendored
@ -4,19 +4,19 @@
|
|||||||
only: issues
|
only: issues
|
||||||
|
|
||||||
# Number of days of inactivity before an issue becomes stale
|
# Number of days of inactivity before an issue becomes stale
|
||||||
daysUntilStale: 14
|
daysUntilStale: 45
|
||||||
|
|
||||||
# Number of days of inactivity before a stale issue is closed
|
# Number of days of inactivity before a stale issue is closed
|
||||||
daysUntilClose: 7
|
daysUntilClose: 15
|
||||||
|
|
||||||
# Issues with these labels will never be considered stale
|
# Issues with these labels will never be considered stale
|
||||||
exemptLabels:
|
exemptLabels:
|
||||||
- "status: accepted"
|
- "status: accepted"
|
||||||
- "status: gathering feedback"
|
|
||||||
- "status: blocked"
|
- "status: blocked"
|
||||||
|
- "status: needs milestone"
|
||||||
|
|
||||||
# Label to use when marking an issue as stale
|
# Label to use when marking an issue as stale
|
||||||
staleLabel: wontfix
|
staleLabel: "pending closure"
|
||||||
|
|
||||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||||
markComment: >
|
markComment: >
|
||||||
|
@ -99,6 +99,10 @@ help prevent wasting time on something that might we might not be able to
|
|||||||
implement. When suggesting a new feature, also make sure it won't conflict with
|
implement. When suggesting a new feature, also make sure it won't conflict with
|
||||||
any work that's already in progress.
|
any work that's already in progress.
|
||||||
|
|
||||||
|
* Once you've opened or identified an issue you'd like to work on, ask that it
|
||||||
|
be assigned to you so that others are aware it's being worked on. A maintainer
|
||||||
|
will then mark the issue as "accepted."
|
||||||
|
|
||||||
* Any pull request which does _not_ relate to an accepted issue will be closed.
|
* Any pull request which does _not_ relate to an accepted issue will be closed.
|
||||||
|
|
||||||
* All major new functionality must include relevant tests where applicable.
|
* All major new functionality must include relevant tests where applicable.
|
||||||
@ -132,18 +136,17 @@ accumulating a large backlog of work.
|
|||||||
The core maintainers group has chosen to make use of GitHub's [Stale bot](https://github.com/apps/stale)
|
The core maintainers group has chosen to make use of GitHub's [Stale bot](https://github.com/apps/stale)
|
||||||
to aid in issue management.
|
to aid in issue management.
|
||||||
|
|
||||||
* Issues will be marked as stale after 14 days of no activity.
|
* Issues will be marked as stale after 45 days of no activity.
|
||||||
* Then after 7 more days of inactivity, the issue will be closed.
|
* Then after 15 more days of inactivity, the issue will be closed.
|
||||||
* Any issue bearing one of the following labels will be exempt from all Stale
|
* Any issue bearing one of the following labels will be exempt from all Stale
|
||||||
bot actions:
|
bot actions:
|
||||||
* `status: accepted`
|
* `status: accepted`
|
||||||
* `status: gathering feedback`
|
|
||||||
* `status: blocked`
|
* `status: blocked`
|
||||||
|
* `status: needs milestone`
|
||||||
|
|
||||||
It is natural that some new issues get more attention than others. Often this
|
It is natural that some new issues get more attention than others. Stale bot
|
||||||
is a metric of an issues's overall value to the project. In other cases in
|
helps bring renewed attention to potentially valuable issues that may have been
|
||||||
which issues merely get lost in the shuffle, notifications from Stale bot can
|
overlooked.
|
||||||
bring renewed attention to potentially meaningful issues.
|
|
||||||
|
|
||||||
## Maintainer Guidance
|
## Maintainer Guidance
|
||||||
|
|
||||||
|
@ -279,6 +279,10 @@ http://localhost:8000/api/ipam/prefixes/ | jq ".actions.POST.status.choices"
|
|||||||
|
|
||||||
For most fields, when a filter is passed multiple times, objects matching _any_ of the provided values will be returned. For example, `GET /api/dcim/sites/?name=Foo&name=Bar` will return all sites named "Foo" _or_ "Bar". The exception to this rule is ManyToManyFields which may have multiple values assigned. Tags are the most common example of a ManyToManyField. For example, `GET /api/dcim/sites/?tag=foo&tag=bar` will return only sites tagged with both "foo" _and_ "bar".
|
For most fields, when a filter is passed multiple times, objects matching _any_ of the provided values will be returned. For example, `GET /api/dcim/sites/?name=Foo&name=Bar` will return all sites named "Foo" _or_ "Bar". The exception to this rule is ManyToManyFields which may have multiple values assigned. Tags are the most common example of a ManyToManyField. For example, `GET /api/dcim/sites/?tag=foo&tag=bar` will return only sites tagged with both "foo" _and_ "bar".
|
||||||
|
|
||||||
|
### Excluding Config Contexts
|
||||||
|
|
||||||
|
The rendered config context for devices and VMs is included by default in all API results (list and detail views). Users with large amounts of context data will most likely observe a performance drop when returning multiple objects, particularly with page sizes in the high hundreds or more. To combat this, in cases where the rendered config context is not needed, the query parameter `?exclude=config_context` may be appended to the request URL to exclude the config context data from the API response.
|
||||||
|
|
||||||
### Custom Fields
|
### Custom Fields
|
||||||
|
|
||||||
To filter on a custom field, prepend `cf_` to the field name. For example, the following query will return only sites where a custom field named `foo` is equal to 123:
|
To filter on a custom field, prepend `cf_` to the field name. For example, the following query will return only sites where a custom field named `foo` is equal to 123:
|
||||||
|
@ -30,6 +30,12 @@ Copy the 'configuration.py' you created when first installing to the new version
|
|||||||
# cp netbox-X.Y.Z/netbox/netbox/configuration.py netbox/netbox/netbox/configuration.py
|
# cp netbox-X.Y.Z/netbox/netbox/configuration.py netbox/netbox/netbox/configuration.py
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Copy your local requirements file if used:
|
||||||
|
|
||||||
|
```no-highlight
|
||||||
|
# cp netbox-X.Y.Z/local_requirements.txt netbox/local_requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
Also copy the LDAP configuration if using LDAP:
|
Also copy the LDAP configuration if using LDAP:
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
A power feed identifies the power outlet/drop that goes to a rack and is terminated to a power panel. Power feeds have a supply type (AC/DC), voltage, amperage, and phase type (single/three).
|
A power feed identifies the power outlet/drop that goes to a rack and is terminated to a power panel. Power feeds have a supply type (AC/DC), voltage, amperage, and phase type (single/three).
|
||||||
|
|
||||||
Power feeds are optionally assigned to a rack. In addition, a power port – and only one – can connect to a power feed; in the context of a PDU, the power feed is analogous to the power outlet that a PDU's power port/inlet connects to.
|
Power feeds are optionally assigned to a rack. In addition, a power port may be connected to a power feed. In the context of a PDU, the power feed is analogous to the power outlet that a PDU's power port/inlet connects to.
|
||||||
|
|
||||||
!!! info
|
!!! info
|
||||||
The power usage of a rack is calculated when a power feed (or multiple) is assigned to that rack and connected to a power port.
|
The power usage of a rack is calculated when a power feed (or multiple) is assigned to that rack and connected to a power port.
|
||||||
|
@ -110,6 +110,8 @@ NetBox looks for the `config` variable within a plugin's `__init__.py` to load i
|
|||||||
| `template_extensions` | The dotted path to the list of template extension classes (default: `template_content.template_extensions`) |
|
| `template_extensions` | The dotted path to the list of template extension classes (default: `template_content.template_extensions`) |
|
||||||
| `menu_items` | The dotted path to the list of menu items provided by the plugin (default: `navigation.menu_items`) |
|
| `menu_items` | The dotted path to the list of menu items provided by the plugin (default: `navigation.menu_items`) |
|
||||||
|
|
||||||
|
All required settings must be configured by the user. If a configuration parameter is listed in both `required_settings` and `default_settings`, the default setting will be ignored.
|
||||||
|
|
||||||
### Install the Plugin for Development
|
### Install the Plugin for Development
|
||||||
|
|
||||||
To ease development, it is recommended to go ahead and install the plugin at this point using setuptools' `develop` mode. This will create symbolic links within your Python environment to the plugin development directory. Call `setup.py` from the plugin's root directory with the `develop` argument (instead of `install`):
|
To ease development, it is recommended to go ahead and install the plugin at this point using setuptools' `develop` mode. This will create symbolic links within your Python environment to the plugin development directory. Call `setup.py` from the plugin's root directory with the `develop` argument (instead of `install`):
|
||||||
|
@ -1,13 +1,25 @@
|
|||||||
# NetBox v2.8
|
# NetBox v2.8
|
||||||
|
|
||||||
## v2.8.9 (FUTURE)
|
## v2.8.9 (2020-08-04)
|
||||||
|
|
||||||
|
### Enhancements
|
||||||
|
|
||||||
|
* [#4898](https://github.com/netbox-community/netbox/issues/4898) - Add MAC address search field to interfaces list
|
||||||
|
* [#4899](https://github.com/netbox-community/netbox/issues/4899) - Add MAC address column to interfaces table
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
|
* [#4455](https://github.com/netbox-community/netbox/issues/4455) - Fix ordering of prefixes beneath aggregate when available space is hidden
|
||||||
* [#4875](https://github.com/netbox-community/netbox/issues/4875) - Fix documentation for image attachments
|
* [#4875](https://github.com/netbox-community/netbox/issues/4875) - Fix documentation for image attachments
|
||||||
* [#4876](https://github.com/netbox-community/netbox/issues/4876) - Fix labels for sites in staging or decommissioning status
|
* [#4876](https://github.com/netbox-community/netbox/issues/4876) - Fix labels for sites in staging or decommissioning status
|
||||||
* [#4880](https://github.com/netbox-community/netbox/issues/4880) - Fix remove tagged vlans if not assigned in bulk interface editting
|
* [#4880](https://github.com/netbox-community/netbox/issues/4880) - Fix removal of tagged VLANs if not assigned in bulk interface editing
|
||||||
* [#4887](https://github.com/netbox-community/netbox/issues/4887) - Don't disable NAPALM tabs when device has no primary IP
|
* [#4887](https://github.com/netbox-community/netbox/issues/4887) - Don't disable NAPALM tabs when device has no primary IP
|
||||||
|
* [#4894](https://github.com/netbox-community/netbox/issues/4894) - Fix display of device/VM counts on platforms list
|
||||||
|
* [#4895](https://github.com/netbox-community/netbox/issues/4895) - Force UTF-8 encoding when embedding model documentation
|
||||||
|
* [#4910](https://github.com/netbox-community/netbox/issues/4910) - Unpin redis dependency to fix exception in RQ worker
|
||||||
|
* [#4926](https://github.com/netbox-community/netbox/issues/4926) - Fix ordering of VM interfaces in REST API endpoint
|
||||||
|
* [#4927](https://github.com/netbox-community/netbox/issues/4927) - Fix validation error when updating an existing secret
|
||||||
|
* [#4929](https://github.com/netbox-community/netbox/issues/4929) - Correct log message when creating a new object
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -2703,6 +2703,10 @@ class InterfaceFilterForm(DeviceComponentFilterForm):
|
|||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
mac_address = forms.CharField(
|
||||||
|
required=False,
|
||||||
|
label='MAC address'
|
||||||
|
)
|
||||||
tag = TagFilterField(model)
|
tag = TagFilterField(model)
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,10 +56,49 @@ DEVICE_COUNT = """
|
|||||||
<a href="{% url 'dcim:device_list' %}?role={{ record.slug }}">{{ value|default:0 }}</a>
|
<a href="{% url 'dcim:device_list' %}?role={{ record.slug }}">{{ value|default:0 }}</a>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VM_COUNT = """
|
RACKRESERVATION_ACTIONS = """
|
||||||
|
<a href="{% url 'dcim:rackreservation_changelog' pk=record.pk %}" class="btn btn-default btn-xs" title="Change log">
|
||||||
|
<i class="fa fa-history"></i>
|
||||||
|
</a>
|
||||||
|
{% if perms.dcim.change_rackreservation %}
|
||||||
|
<a href="{% url 'dcim:rackreservation_edit' pk=record.pk %}?return_url={{ request.path }}" class="btn btn-xs btn-warning"><i class="glyphicon glyphicon-pencil" aria-hidden="true"></i></a>
|
||||||
|
{% endif %}
|
||||||
|
"""
|
||||||
|
|
||||||
|
MANUFACTURER_ACTIONS = """
|
||||||
|
<a href="{% url 'dcim:manufacturer_changelog' slug=record.slug %}" class="btn btn-default btn-xs" title="Change log">
|
||||||
|
<i class="fa fa-history"></i>
|
||||||
|
</a>
|
||||||
|
{% if perms.dcim.change_manufacturer %}
|
||||||
|
<a href="{% url 'dcim:manufacturer_edit' slug=record.slug %}?return_url={{ request.path }}" class="btn btn-xs btn-warning"><i class="glyphicon glyphicon-pencil" aria-hidden="true"></i></a>
|
||||||
|
{% endif %}
|
||||||
|
"""
|
||||||
|
|
||||||
|
DEVICEROLE_DEVICE_COUNT = """
|
||||||
|
<a href="{% url 'dcim:device_list' %}?role={{ record.slug }}">{{ value|default:0 }}</a>
|
||||||
|
"""
|
||||||
|
|
||||||
|
DEVICEROLE_VM_COUNT = """
|
||||||
<a href="{% url 'virtualization:virtualmachine_list' %}?role={{ record.slug }}">{{ value|default:0 }}</a>
|
<a href="{% url 'virtualization:virtualmachine_list' %}?role={{ record.slug }}">{{ value|default:0 }}</a>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
DEVICEROLE_ACTIONS = """
|
||||||
|
<a href="{% url 'dcim:devicerole_changelog' slug=record.slug %}" class="btn btn-default btn-xs" title="Change log">
|
||||||
|
<i class="fa fa-history"></i>
|
||||||
|
</a>
|
||||||
|
{% if perms.dcim.change_devicerole %}
|
||||||
|
<a href="{% url 'dcim:devicerole_edit' slug=record.slug %}?return_url={{ request.path }}" class="btn btn-xs btn-warning"><i class="glyphicon glyphicon-pencil" aria-hidden="true"></i></a>
|
||||||
|
{% endif %}
|
||||||
|
"""
|
||||||
|
|
||||||
|
PLATFORM_DEVICE_COUNT = """
|
||||||
|
<a href="{% url 'dcim:device_list' %}?platform={{ record.slug }}">{{ value|default:0 }}</a>
|
||||||
|
"""
|
||||||
|
|
||||||
|
PLATFORM_VM_COUNT = """
|
||||||
|
<a href="{% url 'virtualization:virtualmachine_list' %}?platform={{ record.slug }}">{{ value|default:0 }}</a>
|
||||||
|
"""
|
||||||
|
|
||||||
STATUS_LABEL = """
|
STATUS_LABEL = """
|
||||||
<span class="label label-{{ record.get_status_class }}">{{ record.get_status_display }}</span>
|
<span class="label label-{{ record.get_status_class }}">{{ record.get_status_display }}</span>
|
||||||
"""
|
"""
|
||||||
@ -495,11 +534,11 @@ class DeviceBayTemplateTable(ComponentTemplateTable):
|
|||||||
class DeviceRoleTable(BaseTable):
|
class DeviceRoleTable(BaseTable):
|
||||||
pk = ToggleColumn()
|
pk = ToggleColumn()
|
||||||
device_count = tables.TemplateColumn(
|
device_count = tables.TemplateColumn(
|
||||||
template_code=DEVICE_COUNT,
|
template_code=DEVICEROLE_DEVICE_COUNT,
|
||||||
verbose_name='Devices'
|
verbose_name='Devices'
|
||||||
)
|
)
|
||||||
vm_count = tables.TemplateColumn(
|
vm_count = tables.TemplateColumn(
|
||||||
template_code=VM_COUNT,
|
template_code=DEVICEROLE_VM_COUNT,
|
||||||
verbose_name='VMs'
|
verbose_name='VMs'
|
||||||
)
|
)
|
||||||
color = tables.TemplateColumn(
|
color = tables.TemplateColumn(
|
||||||
@ -522,11 +561,11 @@ class DeviceRoleTable(BaseTable):
|
|||||||
class PlatformTable(BaseTable):
|
class PlatformTable(BaseTable):
|
||||||
pk = ToggleColumn()
|
pk = ToggleColumn()
|
||||||
device_count = tables.TemplateColumn(
|
device_count = tables.TemplateColumn(
|
||||||
template_code=DEVICE_COUNT,
|
template_code=PLATFORM_DEVICE_COUNT,
|
||||||
verbose_name='Devices'
|
verbose_name='Devices'
|
||||||
)
|
)
|
||||||
vm_count = tables.TemplateColumn(
|
vm_count = tables.TemplateColumn(
|
||||||
template_code=VM_COUNT,
|
template_code=PLATFORM_VM_COUNT,
|
||||||
verbose_name='VMs'
|
verbose_name='VMs'
|
||||||
)
|
)
|
||||||
actions = ButtonsColumn(Platform, pk_field='slug')
|
actions = ButtonsColumn(Platform, pk_field='slug')
|
||||||
@ -718,8 +757,8 @@ class InterfaceTable(DeviceComponentTable, BaseInterfaceTable):
|
|||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = Interface
|
model = Interface
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'device', 'name', 'label', 'enabled', 'type', 'mgmt_only', 'mtu', 'mode', 'description', 'cable',
|
'pk', 'device', 'name', 'label', 'enabled', 'type', 'mgmt_only', 'mtu', 'mode', 'mac_address',
|
||||||
'ip_addresses', 'untagged_vlan', 'tagged_vlans',
|
'description', 'cable', 'ip_addresses', 'untagged_vlan', 'tagged_vlans',
|
||||||
)
|
)
|
||||||
default_columns = ('pk', 'device', 'name', 'label', 'enabled', 'type', 'description')
|
default_columns = ('pk', 'device', 'name', 'label', 'enabled', 'type', 'description')
|
||||||
|
|
||||||
|
@ -953,8 +953,8 @@ class DeviceRoleBulkDeleteView(BulkDeleteView):
|
|||||||
|
|
||||||
class PlatformListView(ObjectListView):
|
class PlatformListView(ObjectListView):
|
||||||
queryset = Platform.objects.annotate(
|
queryset = Platform.objects.annotate(
|
||||||
device_count=get_subquery(Device, 'device_role'),
|
device_count=get_subquery(Device, 'platform'),
|
||||||
vm_count=get_subquery(VirtualMachine, 'role')
|
vm_count=get_subquery(VirtualMachine, 'platform')
|
||||||
)
|
)
|
||||||
table = tables.PlatformTable
|
table = tables.PlatformTable
|
||||||
|
|
||||||
|
@ -219,6 +219,8 @@ class AggregateView(ObjectView):
|
|||||||
prefix__net_contained_or_equal=str(aggregate.prefix)
|
prefix__net_contained_or_equal=str(aggregate.prefix)
|
||||||
).prefetch_related(
|
).prefetch_related(
|
||||||
'site', 'role'
|
'site', 'role'
|
||||||
|
).order_by(
|
||||||
|
'prefix'
|
||||||
).annotate_depth(
|
).annotate_depth(
|
||||||
limit=0
|
limit=0
|
||||||
)
|
)
|
||||||
|
@ -16,7 +16,7 @@ from django.core.validators import URLValidator
|
|||||||
# Environment setup
|
# Environment setup
|
||||||
#
|
#
|
||||||
|
|
||||||
VERSION = '2.9-beta1'
|
VERSION = '2.9-beta2'
|
||||||
|
|
||||||
# Hostname
|
# Hostname
|
||||||
HOSTNAME = platform.node()
|
HOSTNAME = platform.node()
|
||||||
|
@ -121,7 +121,7 @@ class SecretForm(BootstrapMixin, CustomFieldModelForm):
|
|||||||
device=self.cleaned_data['device'],
|
device=self.cleaned_data['device'],
|
||||||
role=self.cleaned_data['role'],
|
role=self.cleaned_data['role'],
|
||||||
name=self.cleaned_data['name']
|
name=self.cleaned_data['name']
|
||||||
).exists():
|
).exclude(pk=self.instance.pk).exists():
|
||||||
raise forms.ValidationError(
|
raise forms.ValidationError(
|
||||||
"Each secret assigned to a device must have a unique combination of role and name"
|
"Each secret assigned to a device must have a unique combination of role and name"
|
||||||
)
|
)
|
||||||
|
@ -178,7 +178,7 @@ def get_docs(model):
|
|||||||
model._meta.model_name
|
model._meta.model_name
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
with open(path) as docfile:
|
with open(path, encoding='utf-8') as docfile:
|
||||||
content = docfile.read()
|
content = docfile.read()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
return "Unable to load documentation, file not found: {}".format(path)
|
return "Unable to load documentation, file not found: {}".format(path)
|
||||||
|
@ -418,13 +418,14 @@ class ObjectEditView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
|
object_created = form.instance.pk is None
|
||||||
obj = form.save()
|
obj = form.save()
|
||||||
|
|
||||||
# Check that the new object conforms with any assigned object-level permissions
|
# Check that the new object conforms with any assigned object-level permissions
|
||||||
self.queryset.get(pk=obj.pk)
|
self.queryset.get(pk=obj.pk)
|
||||||
|
|
||||||
msg = '{} {}'.format(
|
msg = '{} {}'.format(
|
||||||
'Created' if not form.instance.pk else 'Modified',
|
'Created' if object_created else 'Modified',
|
||||||
self.queryset.model._meta.verbose_name
|
self.queryset.model._meta.verbose_name
|
||||||
)
|
)
|
||||||
logger.info(f"{msg} {obj} (PK: {obj.pk})")
|
logger.info(f"{msg} {obj} (PK: {obj.pk})")
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from django.db.models import Count, Prefetch
|
from django.db.models import Count
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
@ -7,7 +7,6 @@ from dcim.models import Device
|
|||||||
from extras.api.serializers import RenderedGraphSerializer
|
from extras.api.serializers import RenderedGraphSerializer
|
||||||
from extras.api.views import CustomFieldModelViewSet
|
from extras.api.views import CustomFieldModelViewSet
|
||||||
from extras.models import Graph
|
from extras.models import Graph
|
||||||
from ipam.models import VLAN
|
|
||||||
from utilities.api import ModelViewSet
|
from utilities.api import ModelViewSet
|
||||||
from utilities.utils import get_subquery
|
from utilities.utils import get_subquery
|
||||||
from virtualization import filters
|
from virtualization import filters
|
||||||
|
@ -20,5 +20,4 @@ Pillow==7.2.0
|
|||||||
psycopg2-binary==2.8.5
|
psycopg2-binary==2.8.5
|
||||||
pycryptodome==3.9.8
|
pycryptodome==3.9.8
|
||||||
PyYAML==5.3.1
|
PyYAML==5.3.1
|
||||||
redis==3.5.3
|
|
||||||
svgwrite==1.4
|
svgwrite==1.4
|
||||||
|
@ -40,11 +40,12 @@ echo "Installing core dependencies ($COMMAND)..."
|
|||||||
eval $COMMAND || exit 1
|
eval $COMMAND || exit 1
|
||||||
|
|
||||||
# Install optional packages (if any)
|
# Install optional packages (if any)
|
||||||
if [ -f "local_requirements.txt" ]
|
if [ -s "local_requirements.txt" ]; then
|
||||||
then
|
|
||||||
COMMAND="pip3 install -r local_requirements.txt"
|
COMMAND="pip3 install -r local_requirements.txt"
|
||||||
echo "Installing local dependencies ($COMMAND)..."
|
echo "Installing local dependencies ($COMMAND)..."
|
||||||
eval $COMMAND || exit 1
|
eval $COMMAND || exit 1
|
||||||
|
elif [ -f "local_requirements.txt" ]; then
|
||||||
|
echo "Skipping local dependencies (local_requirements.txt is empty)"
|
||||||
else
|
else
|
||||||
echo "Skipping local dependencies (local_requirements.txt not found)"
|
echo "Skipping local dependencies (local_requirements.txt not found)"
|
||||||
fi
|
fi
|
||||||
|
Reference in New Issue
Block a user