Skip to content

Commit 73ca886

Browse files
Merge pull request #9618 from magento-gl/febcomprs
[Bluetooth] Community Pull Requests delivery
2 parents df92deb + c040806 commit 73ca886

File tree

11 files changed

+231
-141
lines changed

11 files changed

+231
-141
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
/**
3+
* Copyright 2024 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Backend\Cron;
9+
10+
use Magento\Framework\Lock\Backend\FileLock;
11+
use Magento\Framework\Lock\LockBackendFactory;
12+
use Psr\Log\LoggerInterface;
13+
14+
class CleanLocks
15+
{
16+
/**
17+
* @param LockBackendFactory $lockFactory
18+
* @param LoggerInterface $logger
19+
*/
20+
public function __construct(
21+
private readonly LockBackendFactory $lockFactory,
22+
private readonly LoggerInterface $logger,
23+
) {
24+
}
25+
26+
/**
27+
* Cron job to cleanup old locks
28+
*/
29+
public function execute(): void
30+
{
31+
$locker = $this->lockFactory->create();
32+
33+
if ($locker instanceof FileLock) {
34+
$numberOfLockFilesDeleted = $locker->cleanupOldLocks();
35+
36+
$this->logger->info(sprintf('Deleted %d old lock files', $numberOfLockFilesDeleted));
37+
}
38+
}
39+
}
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
<?xml version="1.0"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2015 Adobe
5+
* All Rights Reserved.
66
*/
77
-->
88
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
99
<group id="default">
1010
<job name="backend_clean_cache" instance="Magento\Backend\Cron\CleanCache" method="execute">
1111
<schedule>30 2 * * *</schedule>
1212
</job>
13+
<job name="backend_clean_locks" instance="Magento\Backend\Cron\CleanLocks" method="execute">
14+
<schedule>20 2 * * *</schedule>
15+
</job>
1316
</group>
1417
</config>

app/code/Magento/ImportExport/Model/Import.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2011 Adobe
4+
* All Rights Reserved.
55
*/
66

77
namespace Magento\ImportExport\Model;
@@ -79,7 +79,7 @@ class Import extends AbstractModel
7979
public const FIELD_NAME_ALLOWED_ERROR_COUNT = 'allowed_error_count';
8080

8181
/**
82-
* Validation startegt field name
82+
* Validation strategy field name
8383
*/
8484
public const FIELD_NAME_VALIDATION_STRATEGY = 'validation_strategy';
8585

@@ -904,7 +904,7 @@ protected function createHistoryReport($sourceFileRelative, $entity, $extension
904904
$this->_varDirectory->writeFile($copyFile, $content);
905905
}
906906
} catch (FileSystemException $e) {
907-
throw new LocalizedException(__('Source file coping failed'));
907+
throw new LocalizedException(__('Source file copying failed'));
908908
}
909909
$this->importHistoryModel->addReport($copyName);
910910
}

app/code/Magento/ImportExport/Test/Unit/Model/ImportTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2015 Adobe
4+
* All Rights Reserved.
55
*/
66
declare(strict_types=1);
77

@@ -1011,7 +1011,7 @@ public function testCreateHistoryReportExtensionIsSet()
10111011
public function testCreateHistoryReportThrowException()
10121012
{
10131013
$this->expectException(LocalizedException::class);
1014-
$this->expectExceptionMessage('Source file coping failed');
1014+
$this->expectExceptionMessage('Source file copying failed');
10151015
$sourceFileRelative = null;
10161016
$entity = '';
10171017
$extension = '';

app/code/Magento/ImportExport/i18n/en_US.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ Status,Status
9090
"Import data validation is complete.","Import data validation is complete."
9191
"The behavior token for %1 is invalid.","The behavior token for %1 is invalid."
9292
"Please enter a correct entity model","Please enter a correct entity model"
93-
"Source file coping failed","Source file coping failed"
93+
"Source file copying failed","Source file copying failed"
9494
"The source is not set.","The source is not set."
9595
"The adapter type must be a non-empty string.","The adapter type must be a non-empty string."
9696
"'%1' file extension is not supported","'%1' file extension is not supported"

app/code/Magento/Theme/view/frontend/templates/html/title.phtml

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,36 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2015 Adobe
4+
* All Rights Reserved.
5+
*/
6+
/**
7+
* Escaper
8+
*
9+
* @var \Magento\Framework\Escaper
510
*/
6-
711
/**
812
* @var $block \Magento\Theme\Block\Html\Title
913
*/
1014
$cssClass = $block->getCssClass() ? ' ' . $block->getCssClass() : '';
1115
$titleHtml = '';
12-
if (trim($block->getPageHeading())) {
16+
17+
$pageHeading = $block->getPageHeading() ? trim($block->getPageHeading()) : '';
18+
19+
if ($pageHeading) {
1320
$titleHtml = '<span class="base" data-ui-id="page-title-wrapper" '
1421
. $block->getAddBaseAttribute()
1522
. '>'
16-
. $block->escapeHtml($block->getPageHeading())
23+
. $escaper->escapeHtml($pageHeading)
1724
. '</span>';
1825
}
1926
?>
20-
<?php if ($titleHtml) : ?>
21-
<div class="page-title-wrapper<?= $block->escapeHtmlAttr($cssClass) ?>">
27+
28+
<?php if ($titleHtml): ?>
29+
<div class="page-title-wrapper<?= $escaper->escapeHtmlAttr($cssClass) ?>">
2230
<h1 class="page-title"
23-
<?php if ($block->getId()) : ?> id="<?= $block->escapeHtmlAttr($block->getId()) ?>" <?php endif; ?>
24-
<?php if ($block->getAddBaseAttributeAria()) : ?>
25-
aria-labelledby="<?= $block->escapeHtmlAttr($block->getAddBaseAttributeAria()) ?>"
31+
<?php if ($block->getId()): ?> id="<?= $escaper->escapeHtmlAttr($block->getId()) ?>" <?php endif; ?>
32+
<?php if ($block->getAddBaseAttributeAria()): ?>
33+
aria-labelledby="<?= $escaper->escapeHtmlAttr($block->getAddBaseAttributeAria()) ?>"
2634
<?php endif; ?>>
2735
<?= /* @noEscape */ $titleHtml ?>
2836
</h1>

app/code/Magento/User/view/adminhtml/web/js/roles-tree.js

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
define([
1010
'jquery',
1111
'jquery/ui',
12-
'jquery/jstree/jquery.jstree'
12+
'jquery/jstree/jquery.jstree',
13+
'mage/translate'
1314
], function ($) {
1415
'use strict';
1516

17+
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
1618
$.widget('mage.rolesTree', {
1719
options: {
1820
treeInitData: {},
@@ -26,9 +28,7 @@ define([
2628
this.element.jstree({
2729
plugins: ['checkbox'],
2830
checkbox: {
29-
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
3031
three_state: false,
31-
// jscs:enable requireCamelCaseOrUpperCaseIdentifiers
3232
visible: this.options.checkboxVisible,
3333
cascade: 'undetermined'
3434
},
@@ -40,13 +40,66 @@ define([
4040
}
4141
});
4242
this._bind();
43+
this._createButtons();
44+
},
45+
46+
_createButtons: function () {
47+
const $tree = $.jstree.reference(this.element),
48+
collapseAllButton = document.createElement('button'),
49+
expandAllButton = document.createElement('button'),
50+
expandUsedButton = document.createElement('button'),
51+
parent = this.element[0],
52+
ul = this.element.find('ul')[0];
53+
54+
collapseAllButton.innerText = $.mage.__('Collapse all');
55+
collapseAllButton.addEventListener('click', function () {
56+
$tree.close_all();
57+
});
58+
59+
expandAllButton.innerText = $.mage.__('Expand all');
60+
expandAllButton.addEventListener('click', function () {
61+
$tree.open_all();
62+
});
63+
64+
expandUsedButton.innerText = $.mage.__('Expand selected');
65+
expandUsedButton.addEventListener('click', function () {
66+
const hasOpened = [];
67+
68+
$tree.get_checked(true).forEach(function (node) {
69+
$tree.open_node(node);
70+
hasOpened.push(node.id);
71+
for (let i = 0; i < node.parents.length - 1; i++) {
72+
const id = node.parents[i];
73+
74+
if (!hasOpened.includes(id)) {
75+
$tree.open_node($tree.get_node(id));
76+
hasOpened.push(id);
77+
}
78+
}
79+
});
80+
});
81+
82+
this.buttons = [
83+
collapseAllButton,
84+
expandAllButton,
85+
expandUsedButton
86+
];
87+
88+
this.buttons.forEach(function (button) {
89+
button.type = 'button';
90+
parent.insertBefore(button, ul);
91+
});
4392
},
4493

4594
/**
4695
* @private
4796
*/
4897
_destroy: function () {
4998
this.element.jstree('destroy');
99+
100+
this.buttons.forEach(function (element) {
101+
element.parentNode.removeChild(element);
102+
});
50103
},
51104

52105
/**
@@ -64,7 +117,6 @@ define([
64117
* @private
65118
*/
66119
_selectChildNodes: function (event, selected) {
67-
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
68120
selected.instance.open_node(selected.node);
69121
selected.node.children.each(function (id) {
70122
var selector = '[id="' + id + '"]';
@@ -73,7 +125,6 @@ define([
73125
selected.instance.get_node($(selector), false)
74126
);
75127
});
76-
// jscs:enable requireCamelCaseOrUpperCaseIdentifiers
77128
},
78129

79130
/**

dev/tests/integration/testsuite/Magento/Framework/Lock/Backend/FileLockTest.php

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2019 Adobe
4+
* All Rights Reserved.
55
*/
66
declare(strict_types=1);
77

@@ -22,12 +22,16 @@ class FileLockTest extends \PHPUnit\Framework\TestCase
2222
*/
2323
private $objectManager;
2424

25+
/** @var string */
26+
private string $lockPath;
27+
2528
protected function setUp(): void
2629
{
30+
$this->lockPath = '/tmp/magento-test-locks';
2731
$this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
2832
$this->model = $this->objectManager->create(
2933
\Magento\Framework\Lock\Backend\FileLock::class,
30-
['path' => '/tmp']
34+
['path' => $this->lockPath]
3135
);
3236
}
3337

@@ -52,4 +56,28 @@ public function testUnlockWithoutExistingLock()
5256
$this->assertFalse($this->model->isLocked($name));
5357
$this->assertFalse($this->model->unlock($name));
5458
}
59+
60+
public function testCleanupOldFile()
61+
{
62+
$name = 'test_lock';
63+
64+
$this->assertTrue($this->model->lock($name));
65+
$this->assertTrue($this->model->unlock($name));
66+
67+
touch(sprintf('%s/%s', $this->lockPath, $name), strtotime('30 hours ago'));
68+
69+
$this->assertEquals(1, $this->model->cleanupOldLocks());
70+
}
71+
72+
public function testDontCleanupNewFile()
73+
{
74+
$name = 'test_lock';
75+
76+
$this->assertTrue($this->model->lock($name));
77+
$this->assertTrue($this->model->unlock($name));
78+
79+
touch(sprintf('%s/%s', $this->lockPath, $name), strtotime('1 hour ago'));
80+
81+
$this->assertEquals(0, $this->model->cleanupOldLocks());
82+
}
5583
}

lib/internal/Magento/Framework/Lock/Backend/FileLock.php

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2019 Adobe
4+
* All Rights Reserved.
55
*/
66
declare(strict_types=1);
77

@@ -42,7 +42,7 @@ class FileLock implements LockManagerInterface
4242
/**
4343
* The mapping list of the path lock with the file resource
4444
*
45-
* @var array
45+
* @var array<string, resource>
4646
*/
4747
private $locks = [];
4848

@@ -105,6 +105,49 @@ public function lock(string $name, int $timeout = -1): bool
105105
return true;
106106
}
107107

108+
/**
109+
* Find lock files that haven't been touched in the last 24 hours, are 0 bytes and are unlocked, then delete those
110+
*/
111+
public function cleanupOldLocks(): int
112+
{
113+
if (!$this->fileDriver->isExists($this->path)) {
114+
return 0;
115+
}
116+
117+
$numberOfLocksDeleted = 0;
118+
$timestamp24HoursAgo = strtotime('24 hours ago');
119+
120+
$lockFiles = $this->fileDriver->readDirectory($this->path);
121+
foreach ($lockFiles as $lockFile) {
122+
if (!$this->fileDriver->isFile($lockFile)) {
123+
continue;
124+
}
125+
126+
$modifiedTimestamp = filemtime($lockFile);
127+
if ($timestamp24HoursAgo < $modifiedTimestamp) {
128+
continue;
129+
}
130+
131+
$filesize = filesize($lockFile);
132+
if ($filesize !== 0) {
133+
continue;
134+
}
135+
136+
if ($this->isLocked(basename($lockFile))) {
137+
continue;
138+
}
139+
140+
try {
141+
$this->fileDriver->deleteFile($lockFile);
142+
++$numberOfLocksDeleted;
143+
} catch (FileSystemException $exception) { // phpcs:ignore Magento2.CodeAnalysis.EmptyBlock.DetectedCatch
144+
// do nothing
145+
}
146+
}
147+
148+
return $numberOfLocksDeleted;
149+
}
150+
108151
/**
109152
* Checks if a lock exists by name
110153
*

0 commit comments

Comments
 (0)