├── .github
└── workflows
│ ├── appstore-build-publish.yml
│ ├── integration.yml
│ ├── lint-info-xml.yml
│ ├── lint-php-cs.yml
│ ├── lint-php.yml
│ ├── phpunit-mysql.yml
│ ├── phpunit-oci.yml
│ ├── phpunit-pgsql.yml
│ ├── phpunit-sqlite.yml
│ ├── psalm-matrix.yml
│ └── update-nextcloud-ocp.yml
├── .gitignore
├── .nextcloudignore
├── .php-cs-fixer.dist.php
├── CHANGELOG.md
├── README.md
├── appinfo
└── info.xml
├── composer.json
├── composer.lock
├── krankerl.toml
├── lib
├── AppInfo
│ └── Application.php
├── INotifyBackendProvider.php
├── LoadBackendListener.php
└── Storage
│ ├── INotifyBackend.php
│ ├── INotifyWrapper.php
│ └── NotifyHandler.php
├── psalm.xml
├── tests
├── Storage
│ └── NotifyHandlerTest.php
├── bootstrap.php
├── phpunit.xml
└── stub.phpstub
└── vendor-bin
├── cs-fixer
├── composer.json
└── composer.lock
├── phpunit
├── composer.json
└── composer.lock
└── psalm
├── composer.json
└── composer.lock
/.github/workflows/appstore-build-publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 |
6 | name: Build and publish app release
7 |
8 | on:
9 | release:
10 | types: [published]
11 |
12 | jobs:
13 | build_and_publish:
14 | runs-on: ubuntu-latest
15 |
16 | # Only allowed to be run on nextcloud-releases repositories
17 | if: ${{ github.repository_owner == 'icewind1991' }}
18 |
19 | steps:
20 | - name: Check actor permission
21 | uses: skjnldsv/check-actor-permission@69e92a3c4711150929bca9fcf34448c5bf5526e7 # v3.0
22 | with:
23 | require: write
24 |
25 | - name: Set app env
26 | run: |
27 | # Split and keep last
28 | echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
29 | echo "APP_VERSION=${GITHUB_REF##*/}" >> $GITHUB_ENV
30 |
31 | - name: Checkout
32 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
33 | with:
34 | path: ${{ env.APP_NAME }}
35 |
36 | - name: Get appinfo data
37 | id: appinfo
38 | uses: skjnldsv/xpath-action@7e6a7c379d0e9abc8acaef43df403ab4fc4f770c # master
39 | with:
40 | filename: ${{ env.APP_NAME }}/appinfo/info.xml
41 | expression: "//info//dependencies//nextcloud/@min-version"
42 |
43 | - name: Read package.json node and npm engines version
44 | uses: skjnldsv/read-package-engines-version-actions@8205673bab74a63eb9b8093402fd9e0e018663a1 # v2.2
45 | id: versions
46 | # Continue if no package.json
47 | continue-on-error: true
48 | with:
49 | path: ${{ env.APP_NAME }}
50 | fallbackNode: '^20'
51 | fallbackNpm: '^10'
52 |
53 | - name: Set up node ${{ steps.versions.outputs.nodeVersion }}
54 | # Skip if no package.json
55 | if: ${{ steps.versions.outputs.nodeVersion }}
56 | uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v3
57 | with:
58 | node-version: ${{ steps.versions.outputs.nodeVersion }}
59 |
60 | - name: Set up npm ${{ steps.versions.outputs.npmVersion }}
61 | # Skip if no package.json
62 | if: ${{ steps.versions.outputs.npmVersion }}
63 | run: npm i -g npm@"${{ steps.versions.outputs.npmVersion }}"
64 |
65 | - name: Get php version
66 | id: php-versions
67 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1
68 | with:
69 | filename: ${{ env.APP_NAME }}/appinfo/info.xml
70 |
71 | - name: Set up php ${{ steps.php-versions.outputs.php-min }}
72 | uses: shivammathur/setup-php@a4e22b60bbb9c1021113f2860347b0759f66fe5d # v2
73 | with:
74 | php-version: ${{ steps.php-versions.outputs.php-min }}
75 | coverage: none
76 | env:
77 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
78 |
79 | - name: Check composer.json
80 | id: check_composer
81 | uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0
82 | with:
83 | files: "${{ env.APP_NAME }}/composer.json"
84 |
85 | - name: Install composer dependencies
86 | if: steps.check_composer.outputs.files_exists == 'true'
87 | run: |
88 | cd ${{ env.APP_NAME }}
89 | composer install --no-dev
90 |
91 | - name: Build ${{ env.APP_NAME }}
92 | # Skip if no package.json
93 | if: ${{ steps.versions.outputs.nodeVersion }}
94 | env:
95 | CYPRESS_INSTALL_BINARY: 0
96 | run: |
97 | cd ${{ env.APP_NAME }}
98 | npm ci
99 | npm run build
100 |
101 | - name: Check Krankerl config
102 | id: krankerl
103 | uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0
104 | with:
105 | files: ${{ env.APP_NAME }}/krankerl.toml
106 |
107 | - name: Install Krankerl
108 | if: steps.krankerl.outputs.files_exists == 'true'
109 | run: |
110 | wget https://github.com/ChristophWurst/krankerl/releases/download/v0.14.0/krankerl_0.14.0_amd64.deb
111 | sudo dpkg -i krankerl_0.14.0_amd64.deb
112 |
113 | - name: Package ${{ env.APP_NAME }} ${{ env.APP_VERSION }} with krankerl
114 | if: steps.krankerl.outputs.files_exists == 'true'
115 | run: |
116 | cd ${{ env.APP_NAME }}
117 | krankerl package
118 |
119 | - name: Package ${{ env.APP_NAME }} ${{ env.APP_VERSION }} with makefile
120 | if: steps.krankerl.outputs.files_exists != 'true'
121 | run: |
122 | cd ${{ env.APP_NAME }}
123 | make appstore
124 |
125 | - name: Checkout server ${{ fromJSON(steps.appinfo.outputs.result).nextcloud.min-version }}
126 | continue-on-error: true
127 | id: server-checkout
128 | run: |
129 | NCVERSION=${{ fromJSON(steps.appinfo.outputs.result).nextcloud.min-version }}
130 | wget --quiet https://download.nextcloud.com/server/releases/latest-$NCVERSION.zip
131 | unzip latest-$NCVERSION.zip
132 |
133 | - name: Checkout server master fallback
134 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
135 | if: ${{ steps.server-checkout.outcome != 'success' }}
136 | with:
137 | submodules: true
138 | repository: nextcloud/server
139 | path: nextcloud
140 |
141 | - name: Sign app
142 | run: |
143 | # Extracting release
144 | cd ${{ env.APP_NAME }}/build/artifacts
145 | tar -xvf ${{ env.APP_NAME }}.tar.gz
146 | cd ../../../
147 | # Setting up keys
148 | echo "${{ secrets.APP_PRIVATE_KEY }}" > ${{ env.APP_NAME }}.key
149 | wget --quiet "https://github.com/nextcloud/app-certificate-requests/raw/master/${{ env.APP_NAME }}/${{ env.APP_NAME }}.crt"
150 | # Signing
151 | php nextcloud/occ integrity:sign-app --privateKey=../${{ env.APP_NAME }}.key --certificate=../${{ env.APP_NAME }}.crt --path=../${{ env.APP_NAME }}/build/artifacts/${{ env.APP_NAME }}
152 | # Rebuilding archive
153 | cd ${{ env.APP_NAME }}/build/artifacts
154 | tar -zcvf ${{ env.APP_NAME }}.tar.gz ${{ env.APP_NAME }}
155 |
156 | - name: Attach tarball to github release
157 | uses: svenstaro/upload-release-action@04733e069f2d7f7f0b4aebc4fbdbce8613b03ccd # v2
158 | id: attach_to_release
159 | with:
160 | repo_token: ${{ secrets.GITHUB_TOKEN }}
161 | file: ${{ env.APP_NAME }}/build/artifacts/${{ env.APP_NAME }}.tar.gz
162 | asset_name: ${{ env.APP_NAME }}-${{ env.APP_VERSION }}.tar.gz
163 | tag: ${{ github.ref }}
164 | overwrite: true
165 |
166 | - name: Upload app to Nextcloud appstore
167 | uses: nextcloud-releases/nextcloud-appstore-push-action@a011fe619bcf6e77ddebc96f9908e1af4071b9c1 # v1
168 | with:
169 | app_name: ${{ env.APP_NAME }}
170 | appstore_token: ${{ secrets.APPSTORE_TOKEN }}
171 | download_url: ${{ steps.attach_to_release.outputs.browser_download_url }}
172 | app_private_key: ${{ secrets.APP_PRIVATE_KEY }}
173 |
--------------------------------------------------------------------------------
/.github/workflows/integration.yml:
--------------------------------------------------------------------------------
1 | name: Integration tests
2 |
3 | on: pull_request
4 |
5 | permissions:
6 | contents: read
7 |
8 | concurrency:
9 | group: integration-${{ github.head_ref || github.run_id }}
10 | cancel-in-progress: true
11 |
12 | jobs:
13 | matrix:
14 | runs-on: ubuntu-latest
15 | outputs:
16 | matrix: ${{ steps.versions.outputs.matrix }}
17 | steps:
18 | - name: Checkout app
19 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
20 | - name: Get version matrix
21 | id: versions
22 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1
23 |
24 | changes:
25 | runs-on: ubuntu-latest
26 |
27 | outputs:
28 | src: ${{ steps.changes.outputs.src}}
29 |
30 | steps:
31 | - uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
32 | id: changes
33 | continue-on-error: true
34 | with:
35 | filters: |
36 | src:
37 | - '.github/workflows/**'
38 | - 'appinfo/**'
39 | - 'lib/**'
40 | - 'templates/**'
41 | - 'tests/**'
42 | - 'vendor/**'
43 | - 'vendor-bin/**'
44 | - '.php-cs-fixer.dist.php'
45 | - 'composer.json'
46 | - 'composer.lock'
47 |
48 | integration:
49 | runs-on: ubuntu-latest
50 |
51 | needs: [changes, matrix]
52 | if: needs.changes.outputs.src != 'false'
53 |
54 | strategy:
55 | matrix: ${{ fromJson(needs.matrix.outputs.matrix) }}
56 |
57 | name: Integrations - PHP ${{ matrix.php-versions }} Nextcloud ${{ matrix.server-versions }}
58 |
59 | steps:
60 | - name: Set app env
61 | run: |
62 | # Split and keep last
63 | echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
64 |
65 | - name: Checkout server
66 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
67 | with:
68 | submodules: true
69 | repository: nextcloud/server
70 | ref: ${{ matrix.server-versions }}
71 |
72 | - name: Checkout app
73 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
74 | with:
75 | path: apps/${{ env.APP_NAME }}
76 |
77 | - name: Set up php ${{ matrix.php-versions }}
78 | uses: shivammathur/setup-php@81cd5ae0920b34eef300e1775313071038a53429 # v2
79 | with:
80 | php-version: ${{ matrix.php-versions }}
81 | # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
82 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite, inotify
83 | coverage: none
84 | ini-file: development
85 | env:
86 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
87 |
88 | - name: Check composer file existence
89 | id: check_composer
90 | uses: andstor/file-existence-action@20b4d2e596410855db8f9ca21e96fbe18e12930b # v2
91 | with:
92 | files: apps/${{ env.APP_NAME }}/composer.json
93 |
94 | - name: Set up dependencies
95 | # Only run if phpunit config file exists
96 | if: steps.check_composer.outputs.files_exists == 'true'
97 | working-directory: apps/${{ env.APP_NAME }}
98 | run: composer i
99 |
100 | - name: Set up Nextcloud
101 | env:
102 | DB_PORT: 4444
103 | run: |
104 | mkdir data
105 | ./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
106 | ./occ app:enable --force files_external
107 |
108 | - name: Setup local external storage
109 | run: |
110 | mkdir /tmp/ext
111 | ./occ files_external:create local local null::null
112 | ./occ files_external:config 1 datadir /tmp/ext
113 | ./occ files_external:list
114 |
115 | - name: Check that local external storage doesn't support notify without the app
116 | run: |
117 | set +e
118 |
119 | # notify command runs forever, so use timeout to distinguish between "failed to start" and "started running"
120 | timeout 2 ./occ files_external:notify 1
121 | status=$?
122 | echo "exit code: $status"
123 |
124 | set -e
125 |
126 | [ $status -eq 1 ]
127 |
128 | - name: Enable app
129 | run: |
130 | ./occ app:enable --force ${{ env.APP_NAME }}
131 |
132 | - name: Check that local external storage supports notify with the app
133 | run: |
134 | set +e
135 |
136 | # notify command runs forever, so use timeout to distinguish between "failed to start" and "started running"
137 | output=$(timeout 2 ./occ files_external:notify 1 -v )
138 | status=$?
139 | echo "exit code: $status"
140 | echo "output: $output"
141 |
142 | set -e
143 |
144 | [ $status -eq 124 ]
145 | [[ $output == *"Self-test successful"* ]]
146 |
147 | - name: Print logs
148 | if: always()
149 | run: |
150 | cat data/nextcloud.log
151 |
152 | summary:
153 | permissions:
154 | contents: none
155 | runs-on: ubuntu-latest
156 | needs: [changes, integration]
157 |
158 | if: always()
159 |
160 | name: integration-summary
161 |
162 | steps:
163 | - name: Summary status
164 | run: if ${{ needs.changes.outputs.src != 'false' && needs.integration.result != 'success' }}; then exit 1; fi
165 |
--------------------------------------------------------------------------------
/.github/workflows/lint-info-xml.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 |
6 | name: Lint info.xml
7 |
8 | on: pull_request
9 |
10 | permissions:
11 | contents: read
12 |
13 | concurrency:
14 | group: lint-info-xml-${{ github.head_ref || github.run_id }}
15 | cancel-in-progress: true
16 |
17 | jobs:
18 | xml-linters:
19 | runs-on: ubuntu-latest
20 |
21 | name: info.xml lint
22 | steps:
23 | - name: Checkout
24 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
25 |
26 | - name: Download schema
27 | run: wget https://raw.githubusercontent.com/nextcloud/appstore/master/nextcloudappstore/api/v1/release/info.xsd
28 |
29 | - name: Lint info.xml
30 | uses: ChristophWurst/xmllint-action@36f2a302f84f8c83fceea0b9c59e1eb4a616d3c1 # v1.2
31 | with:
32 | xml-file: ./appinfo/info.xml
33 | xml-schema-file: ./info.xsd
34 |
--------------------------------------------------------------------------------
/.github/workflows/lint-php-cs.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 |
6 | name: Lint php-cs
7 |
8 | on: pull_request
9 |
10 | permissions:
11 | contents: read
12 |
13 | concurrency:
14 | group: lint-php-cs-${{ github.head_ref || github.run_id }}
15 | cancel-in-progress: true
16 |
17 | jobs:
18 | lint:
19 | runs-on: ubuntu-latest
20 |
21 | name: php-cs
22 |
23 | steps:
24 | - name: Checkout
25 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
26 |
27 | - name: Get php version
28 | id: versions
29 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1
30 |
31 | - name: Set up php${{ steps.versions.outputs.php-available }}
32 | uses: shivammathur/setup-php@a4e22b60bbb9c1021113f2860347b0759f66fe5d # v2
33 | with:
34 | php-version: ${{ steps.versions.outputs.php-available }}
35 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
36 | coverage: none
37 | ini-file: development
38 | env:
39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40 |
41 | - name: Install dependencies
42 | run: composer i
43 |
44 | - name: Lint
45 | run: composer run cs:check || ( echo 'Please run `composer run cs:fix` to format your code' && exit 1 )
46 |
--------------------------------------------------------------------------------
/.github/workflows/lint-php.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 |
6 | name: Lint php
7 |
8 | on: pull_request
9 |
10 | permissions:
11 | contents: read
12 |
13 | concurrency:
14 | group: lint-php-${{ github.head_ref || github.run_id }}
15 | cancel-in-progress: true
16 |
17 | jobs:
18 | matrix:
19 | runs-on: ubuntu-latest
20 | outputs:
21 | php-versions: ${{ steps.versions.outputs.php-versions }}
22 | steps:
23 | - name: Checkout app
24 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
25 | - name: Get version matrix
26 | id: versions
27 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.0.0
28 |
29 | php-lint:
30 | runs-on: ubuntu-latest
31 | needs: matrix
32 | strategy:
33 | matrix:
34 | php-versions: ${{fromJson(needs.matrix.outputs.php-versions)}}
35 |
36 | name: php-lint
37 |
38 | steps:
39 | - name: Checkout
40 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
41 |
42 | - name: Set up php ${{ matrix.php-versions }}
43 | uses: shivammathur/setup-php@a4e22b60bbb9c1021113f2860347b0759f66fe5d # v2
44 | with:
45 | php-version: ${{ matrix.php-versions }}
46 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
47 | coverage: none
48 | ini-file: development
49 | env:
50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
51 |
52 | - name: Lint
53 | run: composer run lint
54 |
55 | summary:
56 | permissions:
57 | contents: none
58 | runs-on: ubuntu-latest
59 | needs: php-lint
60 |
61 | if: always()
62 |
63 | name: php-lint-summary
64 |
65 | steps:
66 | - name: Summary status
67 | run: if ${{ needs.php-lint.result != 'success' && needs.php-lint.result != 'skipped' }}; then exit 1; fi
68 |
--------------------------------------------------------------------------------
/.github/workflows/phpunit-mysql.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 |
6 | name: PHPUnit MySQL
7 |
8 | on: pull_request
9 |
10 | permissions:
11 | contents: read
12 |
13 | concurrency:
14 | group: phpunit-mysql-${{ github.head_ref || github.run_id }}
15 | cancel-in-progress: true
16 |
17 | jobs:
18 | matrix:
19 | runs-on: ubuntu-latest
20 | outputs:
21 | matrix: ${{ steps.versions.outputs.sparse-matrix }}
22 | steps:
23 | - name: Checkout app
24 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
25 |
26 | - name: Get version matrix
27 | id: versions
28 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1
29 | with:
30 | matrix: '{"mysql-versions": ["8.1"]}'
31 |
32 | changes:
33 | runs-on: ubuntu-latest
34 |
35 | outputs:
36 | src: ${{ steps.changes.outputs.src}}
37 |
38 | steps:
39 | - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
40 | id: changes
41 | continue-on-error: true
42 | with:
43 | filters: |
44 | src:
45 | - '.github/workflows/**'
46 | - 'appinfo/**'
47 | - 'lib/**'
48 | - 'templates/**'
49 | - 'tests/**'
50 | - 'vendor/**'
51 | - 'vendor-bin/**'
52 | - '.php-cs-fixer.dist.php'
53 | - 'composer.json'
54 | - 'composer.lock'
55 |
56 | phpunit-mysql:
57 | runs-on: ubuntu-latest
58 |
59 | needs: [changes, matrix]
60 | if: needs.changes.outputs.src != 'false'
61 |
62 | strategy:
63 | matrix: ${{ fromJson(needs.matrix.outputs.matrix) }}
64 |
65 | name: MySQL ${{ matrix.mysql-versions }} PHP ${{ matrix.php-versions }} Nextcloud ${{ matrix.server-versions }}
66 |
67 | services:
68 | mysql:
69 | image: ghcr.io/nextcloud/continuous-integration-mysql-${{ matrix.mysql-versions }}:latest
70 | ports:
71 | - 4444:3306/tcp
72 | env:
73 | MYSQL_ROOT_PASSWORD: rootpassword
74 | options: --health-cmd="mysqladmin ping" --health-interval 5s --health-timeout 2s --health-retries 10
75 |
76 | steps:
77 | - name: Set app env
78 | run: |
79 | # Split and keep last
80 | echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
81 |
82 | - name: Checkout server
83 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
84 | with:
85 | submodules: true
86 | repository: nextcloud/server
87 | ref: ${{ matrix.server-versions }}
88 |
89 | - name: Checkout app
90 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
91 | with:
92 | path: apps/${{ env.APP_NAME }}
93 |
94 | - name: Set up php ${{ matrix.php-versions }}
95 | uses: shivammathur/setup-php@a4e22b60bbb9c1021113f2860347b0759f66fe5d # v2
96 | with:
97 | php-version: ${{ matrix.php-versions }}
98 | # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
99 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, mysql, pdo_mysql, inotify
100 | coverage: none
101 | ini-file: development
102 | env:
103 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
104 |
105 | - name: Enable ONLY_FULL_GROUP_BY MySQL option
106 | run: |
107 | echo "SET GLOBAL sql_mode=(SELECT CONCAT(@@sql_mode,',ONLY_FULL_GROUP_BY'));" | mysql -h 127.0.0.1 -P 4444 -u root -prootpassword
108 | echo "SELECT @@sql_mode;" | mysql -h 127.0.0.1 -P 4444 -u root -prootpassword
109 |
110 | - name: Check composer file existence
111 | id: check_composer
112 | uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0
113 | with:
114 | files: apps/${{ env.APP_NAME }}/composer.json
115 |
116 | - name: Set up dependencies
117 | # Only run if phpunit config file exists
118 | if: steps.check_composer.outputs.files_exists == 'true'
119 | working-directory: apps/${{ env.APP_NAME }}
120 | run: |
121 | composer i --no-dev
122 | rm composer.lock
123 | composer require phpunit/phpunit ^9
124 |
125 | - name: Set up Nextcloud
126 | env:
127 | DB_PORT: 4444
128 | run: |
129 | mkdir data
130 | ./occ maintenance:install --verbose --database=mysql --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
131 | ./occ app:enable --force ${{ env.APP_NAME }}
132 |
133 | - name: Check PHPUnit script is defined
134 | id: check_phpunit
135 | continue-on-error: true
136 | working-directory: apps/${{ env.APP_NAME }}
137 | run: |
138 | composer run --list | grep "^ test:unit " | wc -l | grep 1
139 |
140 | - name: PHPUnit
141 | # Only run if phpunit config file exists
142 | if: steps.check_phpunit.outcome == 'success'
143 | working-directory: apps/${{ env.APP_NAME }}
144 | run: composer run test:unit
145 |
146 | - name: Check PHPUnit integration script is defined
147 | id: check_integration
148 | continue-on-error: true
149 | working-directory: apps/${{ env.APP_NAME }}
150 | run: |
151 | composer run --list | grep "^ test:integration " | wc -l | grep 1
152 |
153 | - name: Run Nextcloud
154 | # Only run if phpunit integration config file exists
155 | if: steps.check_integration.outcome == 'success'
156 | run: php -S localhost:8080 &
157 |
158 | - name: PHPUnit integration
159 | # Only run if phpunit integration config file exists
160 | if: steps.check_integration.outcome == 'success'
161 | working-directory: apps/${{ env.APP_NAME }}
162 | run: composer run test:integration
163 |
164 | - name: Print logs
165 | if: always()
166 | run: |
167 | cat data/nextcloud.log
168 |
169 | - name: Skipped
170 | # Fail the action when neither unit nor integration tests ran
171 | if: steps.check_phpunit.outcome == 'failure' && steps.check_integration.outcome == 'failure'
172 | run: |
173 | echo 'Neither PHPUnit nor PHPUnit integration tests are specified in composer.json scripts'
174 | exit 1
175 |
176 | summary:
177 | permissions:
178 | contents: none
179 | runs-on: ubuntu-latest
180 | needs: [changes, phpunit-mysql]
181 |
182 | if: always()
183 |
184 | name: phpunit-mysql-summary
185 |
186 | steps:
187 | - name: Summary status
188 | run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-mysql.result != 'success' }}; then exit 1; fi
189 |
--------------------------------------------------------------------------------
/.github/workflows/phpunit-oci.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 |
6 | name: PHPUnit OCI
7 |
8 | on: pull_request
9 |
10 | permissions:
11 | contents: read
12 |
13 | concurrency:
14 | group: phpunit-oci-${{ github.head_ref || github.run_id }}
15 | cancel-in-progress: true
16 |
17 | jobs:
18 | matrix:
19 | runs-on: ubuntu-latest
20 | outputs:
21 | php-version: ${{ steps.versions.outputs.php-available-list }}
22 | server-max: ${{ steps.versions.outputs.branches-max-list }}
23 | steps:
24 | - name: Checkout app
25 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
26 |
27 | - name: Get version matrix
28 | id: versions
29 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1
30 |
31 | changes:
32 | runs-on: ubuntu-latest
33 |
34 | outputs:
35 | src: ${{ steps.changes.outputs.src}}
36 |
37 | steps:
38 | - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
39 | id: changes
40 | continue-on-error: true
41 | with:
42 | filters: |
43 | src:
44 | - '.github/workflows/**'
45 | - 'appinfo/**'
46 | - 'lib/**'
47 | - 'templates/**'
48 | - 'tests/**'
49 | - 'vendor/**'
50 | - 'vendor-bin/**'
51 | - '.php-cs-fixer.dist.php'
52 | - 'composer.json'
53 | - 'composer.lock'
54 |
55 | phpunit-oci:
56 | runs-on: ubuntu-22.04
57 |
58 | needs: [changes, matrix]
59 | if: needs.changes.outputs.src != 'false'
60 |
61 | strategy:
62 | matrix:
63 | php-versions: ${{ fromJson(needs.matrix.outputs.php-version) }}
64 | server-versions: ${{ fromJson(needs.matrix.outputs.server-max) }}
65 |
66 | name: OCI PHP ${{ matrix.php-versions }} Nextcloud ${{ matrix.server-versions }}
67 |
68 | services:
69 | oracle:
70 | image: ghcr.io/gvenzl/oracle-xe:11
71 |
72 | # Provide passwords and other environment variables to container
73 | env:
74 | ORACLE_RANDOM_PASSWORD: true
75 | APP_USER: autotest
76 | APP_USER_PASSWORD: owncloud
77 |
78 | # Forward Oracle port
79 | ports:
80 | - 1521:1521/tcp
81 |
82 | # Provide healthcheck script options for startup
83 | options: >-
84 | --health-cmd healthcheck.sh
85 | --health-interval 10s
86 | --health-timeout 5s
87 | --health-retries 10
88 |
89 | steps:
90 | - name: Set app env
91 | run: |
92 | # Split and keep last
93 | echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
94 |
95 | - name: Checkout server
96 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
97 | with:
98 | submodules: true
99 | repository: nextcloud/server
100 | ref: ${{ matrix.server-versions }}
101 |
102 | - name: Checkout app
103 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
104 | with:
105 | path: apps/${{ env.APP_NAME }}
106 |
107 | - name: Set up php ${{ matrix.php-versions }}
108 | uses: shivammathur/setup-php@a4e22b60bbb9c1021113f2860347b0759f66fe5d # v2
109 | with:
110 | php-version: ${{ matrix.php-versions }}
111 | # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
112 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, oci8, inotify
113 | coverage: none
114 | ini-file: development
115 | env:
116 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
117 |
118 | - name: Check composer file existence
119 | id: check_composer
120 | uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0
121 | with:
122 | files: apps/${{ env.APP_NAME }}/composer.json
123 |
124 | - name: Set up dependencies
125 | # Only run if phpunit config file exists
126 | if: steps.check_composer.outputs.files_exists == 'true'
127 | working-directory: apps/${{ env.APP_NAME }}
128 | run: composer i
129 |
130 | - name: Set up Nextcloud
131 | env:
132 | DB_PORT: 1521
133 | run: |
134 | mkdir data
135 | ./occ maintenance:install --verbose --database=oci --database-name=XE --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=autotest --database-pass=owncloud --admin-user admin --admin-pass admin
136 | ./occ app:enable --force ${{ env.APP_NAME }}
137 |
138 | - name: Check PHPUnit script is defined
139 | id: check_phpunit
140 | continue-on-error: true
141 | working-directory: apps/${{ env.APP_NAME }}
142 | run: |
143 | composer run --list | grep "^ test:unit " | wc -l | grep 1
144 |
145 | - name: PHPUnit
146 | # Only run if phpunit config file exists
147 | if: steps.check_phpunit.outcome == 'success'
148 | working-directory: apps/${{ env.APP_NAME }}
149 | run: composer run test:unit
150 |
151 | - name: Check PHPUnit integration script is defined
152 | id: check_integration
153 | continue-on-error: true
154 | working-directory: apps/${{ env.APP_NAME }}
155 | run: |
156 | composer run --list | grep "^ test:integration " | wc -l | grep 1
157 |
158 | - name: Run Nextcloud
159 | # Only run if phpunit integration config file exists
160 | if: steps.check_integration.outcome == 'success'
161 | run: php -S localhost:8080 &
162 |
163 | - name: PHPUnit integration
164 | # Only run if phpunit integration config file exists
165 | if: steps.check_integration.outcome == 'success'
166 | working-directory: apps/${{ env.APP_NAME }}
167 | run: composer run test:integration
168 |
169 | - name: Print logs
170 | if: always()
171 | run: |
172 | cat data/nextcloud.log
173 |
174 | - name: Skipped
175 | # Fail the action when neither unit nor integration tests ran
176 | if: steps.check_phpunit.outcome == 'failure' && steps.check_integration.outcome == 'failure'
177 | run: |
178 | echo 'Neither PHPUnit nor PHPUnit integration tests are specified in composer.json scripts'
179 | exit 1
180 |
181 | summary:
182 | permissions:
183 | contents: none
184 | runs-on: ubuntu-latest
185 | needs: [changes, phpunit-oci]
186 |
187 | if: always()
188 |
189 | name: phpunit-oci-summary
190 |
191 | steps:
192 | - name: Summary status
193 | run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-oci.result != 'success' }}; then exit 1; fi
194 |
--------------------------------------------------------------------------------
/.github/workflows/phpunit-pgsql.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 |
6 | name: PHPUnit PostgreSQL
7 |
8 | on: pull_request
9 |
10 | permissions:
11 | contents: read
12 |
13 | concurrency:
14 | group: phpunit-pgsql-${{ github.head_ref || github.run_id }}
15 | cancel-in-progress: true
16 |
17 | jobs:
18 | matrix:
19 | runs-on: ubuntu-latest
20 | outputs:
21 | php-version: ${{ steps.versions.outputs.php-available-list }}
22 | server-max: ${{ steps.versions.outputs.branches-max-list }}
23 | steps:
24 | - name: Checkout app
25 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
26 |
27 | - name: Get version matrix
28 | id: versions
29 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1
30 |
31 | changes:
32 | runs-on: ubuntu-latest
33 |
34 | outputs:
35 | src: ${{ steps.changes.outputs.src}}
36 |
37 | steps:
38 | - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
39 | id: changes
40 | continue-on-error: true
41 | with:
42 | filters: |
43 | src:
44 | - '.github/workflows/**'
45 | - 'appinfo/**'
46 | - 'lib/**'
47 | - 'templates/**'
48 | - 'tests/**'
49 | - 'vendor/**'
50 | - 'vendor-bin/**'
51 | - '.php-cs-fixer.dist.php'
52 | - 'composer.json'
53 | - 'composer.lock'
54 |
55 | phpunit-pgsql:
56 | runs-on: ubuntu-latest
57 |
58 | needs: [changes, matrix]
59 | if: needs.changes.outputs.src != 'false'
60 |
61 | strategy:
62 | matrix:
63 | php-versions: ${{ fromJson(needs.matrix.outputs.php-version) }}
64 | server-versions: ${{ fromJson(needs.matrix.outputs.server-max) }}
65 |
66 | name: PostgreSQL PHP ${{ matrix.php-versions }} Nextcloud ${{ matrix.server-versions }}
67 |
68 | services:
69 | postgres:
70 | image: ghcr.io/nextcloud/continuous-integration-postgres-14:latest
71 | ports:
72 | - 4444:5432/tcp
73 | env:
74 | POSTGRES_USER: root
75 | POSTGRES_PASSWORD: rootpassword
76 | POSTGRES_DB: nextcloud
77 | options: --health-cmd pg_isready --health-interval 5s --health-timeout 2s --health-retries 5
78 |
79 | steps:
80 | - name: Set app env
81 | run: |
82 | # Split and keep last
83 | echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
84 |
85 | - name: Checkout server
86 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
87 | with:
88 | submodules: true
89 | repository: nextcloud/server
90 | ref: ${{ matrix.server-versions }}
91 |
92 | - name: Checkout app
93 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
94 | with:
95 | path: apps/${{ env.APP_NAME }}
96 |
97 | - name: Set up php ${{ matrix.php-versions }}
98 | uses: shivammathur/setup-php@a4e22b60bbb9c1021113f2860347b0759f66fe5d # v2
99 | with:
100 | php-version: ${{ matrix.php-versions }}
101 | # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
102 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, pgsql, pdo_pgsql, inotify
103 | coverage: none
104 | ini-file: development
105 | env:
106 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
107 |
108 | - name: Check composer file existence
109 | id: check_composer
110 | uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0
111 | with:
112 | files: apps/${{ env.APP_NAME }}/composer.json
113 |
114 | - name: Set up dependencies
115 | # Only run if phpunit config file exists
116 | if: steps.check_composer.outputs.files_exists == 'true'
117 | working-directory: apps/${{ env.APP_NAME }}
118 | run: composer i
119 |
120 | - name: Set up Nextcloud
121 | env:
122 | DB_PORT: 4444
123 | run: |
124 | mkdir data
125 | ./occ maintenance:install --verbose --database=pgsql --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
126 | ./occ app:enable --force ${{ env.APP_NAME }}
127 |
128 | - name: Check PHPUnit script is defined
129 | id: check_phpunit
130 | continue-on-error: true
131 | working-directory: apps/${{ env.APP_NAME }}
132 | run: |
133 | composer run --list | grep "^ test:unit " | wc -l | grep 1
134 |
135 | - name: PHPUnit
136 | # Only run if phpunit config file exists
137 | if: steps.check_phpunit.outcome == 'success'
138 | working-directory: apps/${{ env.APP_NAME }}
139 | run: composer run test:unit
140 |
141 | - name: Check PHPUnit integration script is defined
142 | id: check_integration
143 | continue-on-error: true
144 | working-directory: apps/${{ env.APP_NAME }}
145 | run: |
146 | composer run --list | grep "^ test:integration " | wc -l | grep 1
147 |
148 | - name: Run Nextcloud
149 | # Only run if phpunit integration config file exists
150 | if: steps.check_integration.outcome == 'success'
151 | run: php -S localhost:8080 &
152 |
153 | - name: PHPUnit integration
154 | # Only run if phpunit integration config file exists
155 | if: steps.check_integration.outcome == 'success'
156 | working-directory: apps/${{ env.APP_NAME }}
157 | run: composer run test:integration
158 |
159 | - name: Print logs
160 | if: always()
161 | run: |
162 | cat data/nextcloud.log
163 |
164 | - name: Skipped
165 | # Fail the action when neither unit nor integration tests ran
166 | if: steps.check_phpunit.outcome == 'failure' && steps.check_integration.outcome == 'failure'
167 | run: |
168 | echo 'Neither PHPUnit nor PHPUnit integration tests are specified in composer.json scripts'
169 | exit 1
170 |
171 | summary:
172 | permissions:
173 | contents: none
174 | runs-on: ubuntu-latest
175 | needs: [changes, phpunit-pgsql]
176 |
177 | if: always()
178 |
179 | name: phpunit-pgsql-summary
180 |
181 | steps:
182 | - name: Summary status
183 | run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-pgsql.result != 'success' }}; then exit 1; fi
184 |
--------------------------------------------------------------------------------
/.github/workflows/phpunit-sqlite.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 |
6 | name: PHPUnit SQLite
7 |
8 | on: pull_request
9 |
10 | permissions:
11 | contents: read
12 |
13 | concurrency:
14 | group: phpunit-sqlite-${{ github.head_ref || github.run_id }}
15 | cancel-in-progress: true
16 |
17 | jobs:
18 | matrix:
19 | runs-on: ubuntu-latest
20 | outputs:
21 | php-version: ${{ steps.versions.outputs.php-available-list }}
22 | server-max: ${{ steps.versions.outputs.branches-max-list }}
23 | steps:
24 | - name: Checkout app
25 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
26 |
27 | - name: Get version matrix
28 | id: versions
29 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1
30 |
31 | changes:
32 | runs-on: ubuntu-latest
33 |
34 | outputs:
35 | src: ${{ steps.changes.outputs.src}}
36 |
37 | steps:
38 | - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
39 | id: changes
40 | continue-on-error: true
41 | with:
42 | filters: |
43 | src:
44 | - '.github/workflows/**'
45 | - 'appinfo/**'
46 | - 'lib/**'
47 | - 'templates/**'
48 | - 'tests/**'
49 | - 'vendor/**'
50 | - 'vendor-bin/**'
51 | - '.php-cs-fixer.dist.php'
52 | - 'composer.json'
53 | - 'composer.lock'
54 |
55 | phpunit-sqlite:
56 | runs-on: ubuntu-latest
57 |
58 | needs: [changes, matrix]
59 | if: needs.changes.outputs.src != 'false'
60 |
61 | strategy:
62 | matrix:
63 | php-versions: ${{ fromJson(needs.matrix.outputs.php-version) }}
64 | server-versions: ${{ fromJson(needs.matrix.outputs.server-max) }}
65 |
66 | name: SQLite PHP ${{ matrix.php-versions }} Nextcloud ${{ matrix.server-versions }}
67 |
68 | steps:
69 | - name: Set app env
70 | run: |
71 | # Split and keep last
72 | echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
73 |
74 | - name: Checkout server
75 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
76 | with:
77 | submodules: true
78 | repository: nextcloud/server
79 | ref: ${{ matrix.server-versions }}
80 |
81 | - name: Checkout app
82 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
83 | with:
84 | path: apps/${{ env.APP_NAME }}
85 |
86 | - name: Set up php ${{ matrix.php-versions }}
87 | uses: shivammathur/setup-php@a4e22b60bbb9c1021113f2860347b0759f66fe5d # v2
88 | with:
89 | php-version: ${{ matrix.php-versions }}
90 | # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
91 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite, inotify
92 | coverage: none
93 | ini-file: development
94 | env:
95 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
96 |
97 | - name: Check composer file existence
98 | id: check_composer
99 | uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0
100 | with:
101 | files: apps/${{ env.APP_NAME }}/composer.json
102 |
103 | - name: Set up dependencies
104 | # Only run if phpunit config file exists
105 | if: steps.check_composer.outputs.files_exists == 'true'
106 | working-directory: apps/${{ env.APP_NAME }}
107 | run: composer i
108 |
109 | - name: Set up Nextcloud
110 | env:
111 | DB_PORT: 4444
112 | run: |
113 | mkdir data
114 | ./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
115 | ./occ app:enable --force ${{ env.APP_NAME }}
116 |
117 | - name: Check PHPUnit script is defined
118 | id: check_phpunit
119 | continue-on-error: true
120 | working-directory: apps/${{ env.APP_NAME }}
121 | run: |
122 | composer run --list | grep "^ test:unit " | wc -l | grep 1
123 |
124 | - name: PHPUnit
125 | # Only run if phpunit config file exists
126 | if: steps.check_phpunit.outcome == 'success'
127 | working-directory: apps/${{ env.APP_NAME }}
128 | run: composer run test:unit
129 |
130 | - name: Check PHPUnit integration script is defined
131 | id: check_integration
132 | continue-on-error: true
133 | working-directory: apps/${{ env.APP_NAME }}
134 | run: |
135 | composer run --list | grep "^ test:integration " | wc -l | grep 1
136 |
137 | - name: Run Nextcloud
138 | # Only run if phpunit integration config file exists
139 | if: steps.check_integration.outcome == 'success'
140 | run: php -S localhost:8080 &
141 |
142 | - name: PHPUnit integration
143 | # Only run if phpunit integration config file exists
144 | if: steps.check_integration.outcome == 'success'
145 | working-directory: apps/${{ env.APP_NAME }}
146 | run: composer run test:integration
147 |
148 | - name: Print logs
149 | if: always()
150 | run: |
151 | cat data/nextcloud.log
152 |
153 | - name: Skipped
154 | # Fail the action when neither unit nor integration tests ran
155 | if: steps.check_phpunit.outcome == 'failure' && steps.check_integration.outcome == 'failure'
156 | run: |
157 | echo 'Neither PHPUnit nor PHPUnit integration tests are specified in composer.json scripts'
158 | exit 1
159 |
160 | summary:
161 | permissions:
162 | contents: none
163 | runs-on: ubuntu-latest
164 | needs: [changes, phpunit-sqlite]
165 |
166 | if: always()
167 |
168 | name: phpunit-sqlite-summary
169 |
170 | steps:
171 | - name: Summary status
172 | run: if ${{ needs.changes.outputs.src != 'false' && needs.phpunit-sqlite.result != 'success' }}; then exit 1; fi
173 |
--------------------------------------------------------------------------------
/.github/workflows/psalm-matrix.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 |
6 | name: Static analysis
7 |
8 | on: pull_request
9 |
10 | concurrency:
11 | group: psalm-${{ github.head_ref || github.run_id }}
12 | cancel-in-progress: true
13 |
14 | jobs:
15 | matrix:
16 | runs-on: ubuntu-latest
17 | outputs:
18 | ocp-matrix: ${{ steps.versions.outputs.ocp-matrix }}
19 | steps:
20 | - name: Checkout app
21 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
22 | - name: Get version matrix
23 | id: versions
24 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1
25 |
26 | static-analysis:
27 | runs-on: ubuntu-latest
28 | needs: matrix
29 | strategy:
30 | # do not stop on another job's failure
31 | fail-fast: false
32 | matrix: ${{ fromJson(needs.matrix.outputs.ocp-matrix) }}
33 |
34 | name: static-psalm-analysis ${{ matrix.ocp-version }}
35 | steps:
36 | - name: Checkout
37 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
38 |
39 | - name: Set up php${{ matrix.php-versions }}
40 | uses: shivammathur/setup-php@a4e22b60bbb9c1021113f2860347b0759f66fe5d # v2
41 | with:
42 | php-version: ${{ matrix.php-versions }}
43 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite, inotify
44 | coverage: none
45 | ini-file: development
46 | env:
47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
48 |
49 | - name: Install dependencies
50 | run: composer i
51 |
52 | - name: Install dependencies
53 | run: composer require --dev nextcloud/ocp:${{ matrix.ocp-version }} --ignore-platform-reqs --with-dependencies
54 |
55 | - name: Run coding standards check
56 | run: composer run psalm
57 |
58 | summary:
59 | runs-on: ubuntu-latest
60 | needs: static-analysis
61 |
62 | if: always()
63 |
64 | name: static-psalm-analysis-summary
65 |
66 | steps:
67 | - name: Summary status
68 | run: if ${{ needs.static-analysis.result != 'success' }}; then exit 1; fi
69 |
--------------------------------------------------------------------------------
/.github/workflows/update-nextcloud-ocp.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 |
6 | name: Update nextcloud/ocp
7 |
8 | on:
9 | workflow_dispatch:
10 | schedule:
11 | - cron: "5 2 * * 0"
12 |
13 | jobs:
14 | update-nextcloud-ocp:
15 | runs-on: ubuntu-latest
16 |
17 | strategy:
18 | fail-fast: false
19 | matrix:
20 | branches: ['main', 'master', 'stable29', 'stable28', 'stable27']
21 |
22 | name: update-nextcloud-ocp-${{ matrix.branches }}
23 |
24 | steps:
25 | - id: checkout
26 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
27 | with:
28 | ref: ${{ matrix.branches }}
29 | submodules: true
30 | continue-on-error: true
31 |
32 | - name: Set up php8.2
33 | if: steps.checkout.outcome == 'success'
34 | uses: shivammathur/setup-php@a4e22b60bbb9c1021113f2860347b0759f66fe5d # v2
35 | with:
36 | php-version: 8.2
37 | # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation
38 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
39 | coverage: none
40 | env:
41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
42 |
43 | - name: Read codeowners
44 | if: steps.checkout.outcome == 'success'
45 | id: codeowners
46 | run: |
47 | grep '/appinfo/info.xml' .github/CODEOWNERS | cut -f 2- -d ' ' | xargs | awk '{ print "codeowners="$0 }' >> $GITHUB_OUTPUT
48 | continue-on-error: true
49 |
50 | - name: Composer install
51 | if: steps.checkout.outcome == 'success'
52 | run: composer install
53 |
54 | - name: Composer update nextcloud/ocp
55 | id: update_branch
56 | if: ${{ steps.checkout.outcome == 'success' && matrix.branches != 'main' }}
57 | run: composer require --dev nextcloud/ocp:dev-${{ matrix.branches }}
58 |
59 | - name: Raise on issue on failure
60 | uses: dacbd/create-issue-action@cdb57ab6ff8862aa09fee2be6ba77a59581921c2 # v2.0.0
61 | if: ${{ steps.checkout.outcome == 'success' && failure() && steps.update_branch.conclusion == 'failure' }}
62 | with:
63 | token: ${{ secrets.GITHUB_TOKEN }}
64 | title: Failed to update nextcloud/ocp package on branch ${{ matrix.branches }}
65 | body: Please check the output of the GitHub action and manually resolve the issues
${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
${{ steps.codeowners.outputs.codeowners }}
66 |
67 | - name: Composer update nextcloud/ocp
68 | id: update_main
69 | if: ${{ steps.checkout.outcome == 'success' && matrix.branches == 'main' }}
70 | run: composer require --dev nextcloud/ocp:dev-master
71 |
72 | - name: Raise on issue on failure
73 | uses: dacbd/create-issue-action@cdb57ab6ff8862aa09fee2be6ba77a59581921c2 # v2.0.0
74 | if: ${{ steps.checkout.outcome == 'success' && failure() && steps.update_main.conclusion == 'failure' }}
75 | with:
76 | token: ${{ secrets.GITHUB_TOKEN }}
77 | title: Failed to update nextcloud/ocp package on branch ${{ matrix.branches }}
78 | body: Please check the output of the GitHub action and manually resolve the issues
${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
${{ steps.codeowners.outputs.codeowners }}
79 |
80 | - name: Reset checkout 3rdparty
81 | if: steps.checkout.outcome == 'success'
82 | run: |
83 | git clean -f 3rdparty
84 | git checkout 3rdparty
85 | continue-on-error: true
86 |
87 | - name: Reset checkout vendor
88 | if: steps.checkout.outcome == 'success'
89 | run: |
90 | git clean -f vendor
91 | git checkout vendor
92 | continue-on-error: true
93 |
94 | - name: Reset checkout vendor-bin
95 | if: steps.checkout.outcome == 'success'
96 | run: |
97 | git clean -f vendor-bin
98 | git checkout vendor-bin
99 | continue-on-error: true
100 |
101 | - name: Create Pull Request
102 | if: steps.checkout.outcome == 'success'
103 | uses: peter-evans/create-pull-request@a4f52f8033a6168103c2538976c07b467e8163bc # v6.0.1
104 | with:
105 | token: ${{ secrets.COMMAND_BOT_PAT }}
106 | commit-message: "chore(dev-deps): Bump nextcloud/ocp package"
107 | committer: GitHub
108 | author: nextcloud-command
109 | signoff: true
110 | branch: automated/noid/${{ matrix.branches }}-update-nextcloud-ocp
111 | title: "[${{ matrix.branches }}] Update nextcloud/ocp dependency"
112 | body: |
113 | Auto-generated update of [nextcloud/ocp](https://github.com/nextcloud-deps/ocp/) dependency
114 | labels: |
115 | dependencies
116 | 3. to review
117 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | vendor
3 | node_modules
4 | *.cache
5 |
--------------------------------------------------------------------------------
/.nextcloudignore:
--------------------------------------------------------------------------------
1 | .drone
2 | .git
3 | .github
4 | .gitignore
5 | .scrutinizer.yml
6 | .travis.yml
7 | .tx
8 | .env
9 | krankerl.toml
10 | screenshots
11 | .nextcloudignore
12 | target
13 | tests
14 | composer.*
15 | .php_cs.dist
16 | psalm*.xml
17 | Dockerfile
18 | node_modules
19 | Makefile
20 |
--------------------------------------------------------------------------------
/.php-cs-fixer.dist.php:
--------------------------------------------------------------------------------
1 | getFinder()
15 | ->ignoreVCSIgnored(true)
16 | ->notPath('build')
17 | ->notPath('tests/stub.phpstub')
18 | ->notPath('l10n')
19 | ->notPath('src')
20 | ->notPath('vendor')
21 | ->in(__DIR__);
22 | return $config;
23 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## v0.1.9
4 | - Compatible with Nextcloud 20 and 21
5 |
6 | ## v0.1.8
7 | - Compatible with Nextcloud 19
8 |
9 | ## v0.1.7
10 | - Compatible with Nextcloud 18
11 |
12 | ## v0.1.6
13 | - Improved handling of interrupted `stream_select` - @tmolitor-stud-tu
14 |
15 | ## v0.1.5
16 | - Compatible with Nextcloud 17
17 |
18 | ## v0.1.4
19 | - Support Nextcloud 16
20 |
21 | ## v0.1.3
22 | - Prevent breaking when files_external is not enabled
23 | - Compatible with Nextcloud 15
24 |
25 | ## v0.1.2
26 | - Fix issue where stream select generates large amount of error logs
27 | - Remove NC11 compatibility
28 |
29 |
30 |
31 | ## v0.1.1
32 | - Mark as compatible with NC13 and NC14
33 |
34 | ## v0.1.0
35 | Initial version with support for Nextcloud 11 and 12
36 |
37 |
38 | ---
39 |
40 | Generated by [changelog](https://github.com/gluons/changelog).
41 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # files_inotify
2 |
3 | [](https://github.com/icewind1991/files_inotify/actions)
4 |
5 | Adds support detecting changes in local external storages with occ files_external:notify
6 |
7 | ## Requirements
8 |
9 | This app uses the php inotify extensions which is required to be installed before this app can be enabled.
10 | The php inotify extension can be installed from your distribution's package or [pecl](https://pecl.php.net/package/inotify).
11 |
12 | ## Usage
13 |
14 | To detect changes you need to run the `files_external:notify` command for the configured local external storage.
15 |
16 | Note that this command runs continuously and should be started in the background by an init system or other task manager for best usage.
17 |
18 | Find the id of the external storage that should be checked
19 |
20 | ```
21 | occ files_external:list
22 |
23 | +----------+-------------+------------+-----------------------+------------------------+------------+------------------+-------------------+
24 | | Mount ID | Mount Point | Storage | Authentication Type | Configuration | Options | Applicable Users | Applicable Groups |
25 | +----------+-------------+------------+-----------------------+------------------------+------------+------------------+-------------------+
26 | | 5 | /test | Local | None | datadir: "....." | | | |
27 | +----------+-------------+------------+-----------------------+------------------------+------------+------------------+-------------------+
28 |
29 | ```
30 |
31 | Run the filesystem watch
32 |
33 | ```
34 | occ files_external:notify -v 5
35 | ```
36 |
37 | ## Scalability notes
38 |
39 | Due to the nature of `inotify` the memory requirements of listening for changes
40 | scales linearly with the number of folders in the storage.
41 |
42 | Additionally it's required to configure `fs.inotify.max_user_watches` on the server
43 | to be higher than the total number of folders being watched.
44 |
--------------------------------------------------------------------------------
/appinfo/info.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | files_inotify
5 | INotify file watcher
6 | Adds support detecting changes in local external storages
7 |
12 |
13 | 0.2.3
14 | agpl
15 | Robin Appelman
16 | Files_INotify
17 |
18 |
19 |
20 |
21 | files
22 |
23 | https://github.com/icewind1991/files_inotify
24 | https://github.com/icewind1991/files_inotify/issues
25 |
26 | https://github.com/icewind1991/files_inotify.git
27 |
28 |
29 |
30 | inotify
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "project",
3 | "require-dev": {
4 | "nextcloud/ocp": "dev-master"
5 | },
6 | "require": {
7 | "bamarni/composer-bin-plugin": "^1.8"
8 | },
9 | "license": "AGPLv3",
10 | "scripts": {
11 | "post-install-cmd": [
12 | "@composer bin all install --ansi"
13 | ],
14 | "post-update-cmd": [
15 | "@composer bin all update --ansi"
16 | ],
17 | "lint": "find . -name \\*.php -not -path './vendor/*' -not -path './vendor-bin/*' -not -path './build/*' -not -path './tests/integration/vendor/*' -print0 | xargs -0 -n1 php -l",
18 | "cs:check": "php-cs-fixer fix --dry-run --diff",
19 | "cs:fix": "php-cs-fixer fix",
20 | "test:unit": "phpunit -c tests/phpunit.xml",
21 | "psalm": "psalm --threads=1",
22 | "psalm:update-baseline": "psalm --threads=1 --update-baseline",
23 | "psalm:clear": "psalm --clear-cache && psalm --clear-global-cache",
24 | "psalm:fix": "psalm --alter --issues=InvalidReturnType,InvalidNullableReturnType,MissingParamType,InvalidFalsableReturnType"
25 | },
26 | "config": {
27 | "allow-plugins": {
28 | "bamarni/composer-bin-plugin": true
29 | },
30 | "platform": {
31 | "php": "8.1"
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "79347efa5966aec068b8ece538e4c21b",
8 | "packages": [
9 | {
10 | "name": "bamarni/composer-bin-plugin",
11 | "version": "1.8.2",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/bamarni/composer-bin-plugin.git",
15 | "reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/bamarni/composer-bin-plugin/zipball/92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880",
20 | "reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "composer-plugin-api": "^2.0",
25 | "php": "^7.2.5 || ^8.0"
26 | },
27 | "require-dev": {
28 | "composer/composer": "^2.0",
29 | "ext-json": "*",
30 | "phpstan/extension-installer": "^1.1",
31 | "phpstan/phpstan": "^1.8",
32 | "phpstan/phpstan-phpunit": "^1.1",
33 | "phpunit/phpunit": "^8.5 || ^9.5",
34 | "symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0",
35 | "symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0",
36 | "symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0"
37 | },
38 | "type": "composer-plugin",
39 | "extra": {
40 | "class": "Bamarni\\Composer\\Bin\\BamarniBinPlugin"
41 | },
42 | "autoload": {
43 | "psr-4": {
44 | "Bamarni\\Composer\\Bin\\": "src"
45 | }
46 | },
47 | "notification-url": "https://packagist.org/downloads/",
48 | "license": [
49 | "MIT"
50 | ],
51 | "description": "No conflicts for your bin dependencies",
52 | "keywords": [
53 | "composer",
54 | "conflict",
55 | "dependency",
56 | "executable",
57 | "isolation",
58 | "tool"
59 | ],
60 | "support": {
61 | "issues": "https://github.com/bamarni/composer-bin-plugin/issues",
62 | "source": "https://github.com/bamarni/composer-bin-plugin/tree/1.8.2"
63 | },
64 | "time": "2022-10-31T08:38:03+00:00"
65 | }
66 | ],
67 | "packages-dev": [
68 | {
69 | "name": "nextcloud/ocp",
70 | "version": "dev-master",
71 | "source": {
72 | "type": "git",
73 | "url": "https://github.com/nextcloud-deps/ocp.git",
74 | "reference": "dc5473e3895d859535de45eab15d2095cb8eafe4"
75 | },
76 | "dist": {
77 | "type": "zip",
78 | "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/dc5473e3895d859535de45eab15d2095cb8eafe4",
79 | "reference": "dc5473e3895d859535de45eab15d2095cb8eafe4",
80 | "shasum": ""
81 | },
82 | "require": {
83 | "php": "~8.1 || ~8.2 || ~8.3 || ~8.4",
84 | "psr/clock": "^1.0",
85 | "psr/container": "^2.0.2",
86 | "psr/event-dispatcher": "^1.0",
87 | "psr/log": "^3.0.2"
88 | },
89 | "default-branch": true,
90 | "type": "library",
91 | "extra": {
92 | "branch-alias": {
93 | "dev-master": "32.0.0-dev"
94 | }
95 | },
96 | "notification-url": "https://packagist.org/downloads/",
97 | "license": [
98 | "AGPL-3.0-or-later"
99 | ],
100 | "authors": [
101 | {
102 | "name": "Christoph Wurst",
103 | "email": "christoph@winzerhof-wurst.at"
104 | },
105 | {
106 | "name": "Joas Schilling",
107 | "email": "coding@schilljs.com"
108 | }
109 | ],
110 | "description": "Composer package containing Nextcloud's public OCP API and the unstable NCU API",
111 | "support": {
112 | "issues": "https://github.com/nextcloud-deps/ocp/issues",
113 | "source": "https://github.com/nextcloud-deps/ocp/tree/master"
114 | },
115 | "time": "2025-03-11T00:46:19+00:00"
116 | },
117 | {
118 | "name": "psr/clock",
119 | "version": "1.0.0",
120 | "source": {
121 | "type": "git",
122 | "url": "https://github.com/php-fig/clock.git",
123 | "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d"
124 | },
125 | "dist": {
126 | "type": "zip",
127 | "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d",
128 | "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d",
129 | "shasum": ""
130 | },
131 | "require": {
132 | "php": "^7.0 || ^8.0"
133 | },
134 | "type": "library",
135 | "autoload": {
136 | "psr-4": {
137 | "Psr\\Clock\\": "src/"
138 | }
139 | },
140 | "notification-url": "https://packagist.org/downloads/",
141 | "license": [
142 | "MIT"
143 | ],
144 | "authors": [
145 | {
146 | "name": "PHP-FIG",
147 | "homepage": "https://www.php-fig.org/"
148 | }
149 | ],
150 | "description": "Common interface for reading the clock.",
151 | "homepage": "https://github.com/php-fig/clock",
152 | "keywords": [
153 | "clock",
154 | "now",
155 | "psr",
156 | "psr-20",
157 | "time"
158 | ],
159 | "support": {
160 | "issues": "https://github.com/php-fig/clock/issues",
161 | "source": "https://github.com/php-fig/clock/tree/1.0.0"
162 | },
163 | "time": "2022-11-25T14:36:26+00:00"
164 | },
165 | {
166 | "name": "psr/container",
167 | "version": "2.0.2",
168 | "source": {
169 | "type": "git",
170 | "url": "https://github.com/php-fig/container.git",
171 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
172 | },
173 | "dist": {
174 | "type": "zip",
175 | "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
176 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
177 | "shasum": ""
178 | },
179 | "require": {
180 | "php": ">=7.4.0"
181 | },
182 | "type": "library",
183 | "extra": {
184 | "branch-alias": {
185 | "dev-master": "2.0.x-dev"
186 | }
187 | },
188 | "autoload": {
189 | "psr-4": {
190 | "Psr\\Container\\": "src/"
191 | }
192 | },
193 | "notification-url": "https://packagist.org/downloads/",
194 | "license": [
195 | "MIT"
196 | ],
197 | "authors": [
198 | {
199 | "name": "PHP-FIG",
200 | "homepage": "https://www.php-fig.org/"
201 | }
202 | ],
203 | "description": "Common Container Interface (PHP FIG PSR-11)",
204 | "homepage": "https://github.com/php-fig/container",
205 | "keywords": [
206 | "PSR-11",
207 | "container",
208 | "container-interface",
209 | "container-interop",
210 | "psr"
211 | ],
212 | "support": {
213 | "issues": "https://github.com/php-fig/container/issues",
214 | "source": "https://github.com/php-fig/container/tree/2.0.2"
215 | },
216 | "time": "2021-11-05T16:47:00+00:00"
217 | },
218 | {
219 | "name": "psr/event-dispatcher",
220 | "version": "1.0.0",
221 | "source": {
222 | "type": "git",
223 | "url": "https://github.com/php-fig/event-dispatcher.git",
224 | "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
225 | },
226 | "dist": {
227 | "type": "zip",
228 | "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
229 | "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
230 | "shasum": ""
231 | },
232 | "require": {
233 | "php": ">=7.2.0"
234 | },
235 | "type": "library",
236 | "extra": {
237 | "branch-alias": {
238 | "dev-master": "1.0.x-dev"
239 | }
240 | },
241 | "autoload": {
242 | "psr-4": {
243 | "Psr\\EventDispatcher\\": "src/"
244 | }
245 | },
246 | "notification-url": "https://packagist.org/downloads/",
247 | "license": [
248 | "MIT"
249 | ],
250 | "authors": [
251 | {
252 | "name": "PHP-FIG",
253 | "homepage": "http://www.php-fig.org/"
254 | }
255 | ],
256 | "description": "Standard interfaces for event handling.",
257 | "keywords": [
258 | "events",
259 | "psr",
260 | "psr-14"
261 | ],
262 | "support": {
263 | "issues": "https://github.com/php-fig/event-dispatcher/issues",
264 | "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
265 | },
266 | "time": "2019-01-08T18:20:26+00:00"
267 | },
268 | {
269 | "name": "psr/log",
270 | "version": "3.0.2",
271 | "source": {
272 | "type": "git",
273 | "url": "https://github.com/php-fig/log.git",
274 | "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
275 | },
276 | "dist": {
277 | "type": "zip",
278 | "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
279 | "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
280 | "shasum": ""
281 | },
282 | "require": {
283 | "php": ">=8.0.0"
284 | },
285 | "type": "library",
286 | "extra": {
287 | "branch-alias": {
288 | "dev-master": "3.x-dev"
289 | }
290 | },
291 | "autoload": {
292 | "psr-4": {
293 | "Psr\\Log\\": "src"
294 | }
295 | },
296 | "notification-url": "https://packagist.org/downloads/",
297 | "license": [
298 | "MIT"
299 | ],
300 | "authors": [
301 | {
302 | "name": "PHP-FIG",
303 | "homepage": "https://www.php-fig.org/"
304 | }
305 | ],
306 | "description": "Common interface for logging libraries",
307 | "homepage": "https://github.com/php-fig/log",
308 | "keywords": [
309 | "log",
310 | "psr",
311 | "psr-3"
312 | ],
313 | "support": {
314 | "source": "https://github.com/php-fig/log/tree/3.0.2"
315 | },
316 | "time": "2024-09-11T13:17:53+00:00"
317 | }
318 | ],
319 | "aliases": [],
320 | "minimum-stability": "stable",
321 | "stability-flags": {
322 | "nextcloud/ocp": 20
323 | },
324 | "prefer-stable": false,
325 | "prefer-lowest": false,
326 | "platform": {},
327 | "platform-dev": {},
328 | "platform-overrides": {
329 | "php": "8.1"
330 | },
331 | "plugin-api-version": "2.6.0"
332 | }
333 |
--------------------------------------------------------------------------------
/krankerl.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | before_cmds = [
3 |
4 | ]
5 |
--------------------------------------------------------------------------------
/lib/AppInfo/Application.php:
--------------------------------------------------------------------------------
1 |
5 | *
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | *
21 | */
22 |
23 | namespace OCA\Files_INotify\AppInfo;
24 |
25 | use OCA\Files_External\Service\BackendService;
26 | use OCA\Files_INotify\INotifyBackendProvider;
27 | use OCP\AppFramework\App;
28 | use OCP\AppFramework\Bootstrap\IBootContext;
29 | use OCP\AppFramework\Bootstrap\IBootstrap;
30 | use OCP\AppFramework\Bootstrap\IRegistrationContext;
31 | use OCP\AppFramework\IAppContainer;
32 | use OCP\EventDispatcher\IEventDispatcher;
33 |
34 | class Application extends App implements IBootstrap {
35 | public function __construct(array $urlParams = []) {
36 | parent::__construct('files_inotify', $urlParams);
37 | }
38 |
39 | public function register(IRegistrationContext $context): void {
40 | }
41 |
42 | public function boot(IBootContext $context): void {
43 | $context->injectFn([$this, 'registerBackendDependents']);
44 | }
45 |
46 | public function registerBackendDependents(IAppContainer $appContainer, IEventDispatcher $dispatcher) {
47 | $dispatcher->addListener(
48 | 'OCA\\Files_External::loadAdditionalBackends',
49 | function () use ($appContainer) {
50 | if (\OC::$CLI && class_exists(BackendService::class)) {
51 | // we can't inject these 2, since they would cause hard errors if files_external is not enabled
52 | /** @var BackendService $backendService */
53 | $backendService = $appContainer->get(BackendService::class);
54 | /** @var INotifyBackendProvider $backendProvider */
55 | $backendProvider = $appContainer->get(INotifyBackendProvider::class);
56 | $backendService->registerBackendProvider($backendProvider);
57 | }
58 | }
59 | );
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/INotifyBackendProvider.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * @license GNU AGPL version 3 or any later version
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as
11 | * published by the Free Software Foundation, either version 3 of the
12 | * License, or (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | *
22 | */
23 |
24 | namespace OCA\Files_INotify;
25 |
26 | use OCA\Files_External\Lib\Config\IBackendProvider;
27 | use OCA\Files_INotify\Storage\INotifyBackend;
28 |
29 | class INotifyBackendProvider implements IBackendProvider {
30 | /** @var INotifyBackend */
31 | private $notifyBackend;
32 |
33 | public function __construct(INotifyBackend $notifyBackend) {
34 | $this->notifyBackend = $notifyBackend;
35 | }
36 |
37 | public function getBackends() {
38 | return [
39 | $this->notifyBackend
40 | ];
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/LoadBackendListener.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * @license GNU AGPL version 3 or any later version
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as
11 | * published by the Free Software Foundation, either version 3 of the
12 | * License, or (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | *
22 | */
23 |
24 | namespace OCA\FilesInotify\lib;
25 |
26 | use OCA\Files_External\Service\BackendService;
27 | use OCA\Files_INotify\INotifyBackendProvider;
28 | use OCP\EventDispatcher\Event;
29 | use OCP\EventDispatcher\IEventListener;
30 |
31 | /**
32 | * @template-implements IEventListener
33 | */
34 | class LoadBackendListener implements IEventListener {
35 | private BackendService $backendService;
36 | private INotifyBackendProvider $backendProvider;
37 |
38 | public function __construct(BackendService $backendService, INotifyBackendProvider $backendProvider) {
39 | $this->backendService = $backendService;
40 | $this->backendProvider = $backendProvider;
41 | }
42 |
43 | public function handle(Event $event): void {
44 | if (\OC::$CLI) {
45 | $this->backendService->registerBackendProvider($this->backendProvider);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/Storage/INotifyBackend.php:
--------------------------------------------------------------------------------
1 |
5 | *
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | *
21 | */
22 |
23 | namespace OCA\Files_INotify\Storage;
24 |
25 | use OCA\Files_External\Lib\Auth\NullMechanism;
26 | use OCA\Files_External\Lib\Backend\Local;
27 | use OCP\IL10N;
28 |
29 | class INotifyBackend extends Local {
30 | public function __construct(IL10N $l, NullMechanism $legacyAuth) {
31 | parent::__construct($l, $legacyAuth);
32 | $this->setStorageClass(INotifyWrapper::class);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/Storage/INotifyWrapper.php:
--------------------------------------------------------------------------------
1 |
5 | *
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | *
21 | */
22 |
23 | namespace OCA\Files_INotify\Storage;
24 |
25 | use OC\Files\Storage\Local;
26 | use OCP\Files\Notify\IChange;
27 | use OCP\Files\Notify\IRenameChange;
28 | use OCP\Files\Storage\INotifyStorage;
29 |
30 | class INotifyWrapper extends Local implements INotifyStorage {
31 | public function listen($path, callable $callback) {
32 | $this->notify($path)->listen(function (IChange $change) use ($callback) {
33 | if ($change instanceof IRenameChange) {
34 | return $callback($change->getType(), $change->getPath(), $change->getTargetPath());
35 | } else {
36 | return $callback($change->getType(), $change->getPath());
37 | }
38 | });
39 | }
40 |
41 | public function notify($path) {
42 | return new NotifyHandler($this->datadir);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/Storage/NotifyHandler.php:
--------------------------------------------------------------------------------
1 |
5 | *
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | *
21 | */
22 |
23 | namespace OCA\Files_INotify\Storage;
24 |
25 | use OC\Files\Notify\Change;
26 | use OC\Files\Notify\RenameChange;
27 | use OCP\Files\Notify\IChange;
28 | use OCP\Files\Notify\INotifyHandler;
29 |
30 | class NotifyHandler implements INotifyHandler {
31 | /** @var resource|null */
32 | private $fd;
33 |
34 | /** @var string */
35 | private $basePath;
36 |
37 | /** @var string[] */
38 | private $pathMap = [];
39 |
40 | /** @var string[][] */
41 | private $moveMap = [];
42 |
43 | /**
44 | * @param string $basePath
45 | */
46 | public function __construct($basePath) {
47 | $this->fd = inotify_init();
48 |
49 | $this->basePath = rtrim($basePath, '/');
50 | $this->register();
51 | }
52 |
53 | private function getDirectoryIterator(string $path): \Iterator {
54 | return new \RecursiveIteratorIterator(
55 | new \RecursiveDirectoryIterator($path,
56 | \FilesystemIterator::CURRENT_AS_PATHNAME + \FilesystemIterator::SKIP_DOTS),
57 | \RecursiveIteratorIterator::SELF_FIRST, \RecursiveIteratorIterator::CATCH_GET_CHILD);
58 | }
59 |
60 | private function register(): void {
61 | $iterator = $this->getDirectoryIterator($this->basePath);
62 |
63 | $this->watchPath($this->basePath);
64 | foreach ($iterator as $path) {
65 | if (is_dir($path)) {
66 | $this->watchPath($path);
67 | }
68 | }
69 | }
70 |
71 | private function watchPath(string $path): void {
72 | if ($this->fd === null) {
73 | return;
74 | }
75 | $descriptor = inotify_add_watch($this->fd, $path,
76 | \IN_MODIFY + \IN_CREATE + \IN_MOVED_FROM + \IN_MOVED_TO + \IN_DELETE);
77 | $this->pathMap[$descriptor] = $path;
78 | }
79 |
80 | /**
81 | * @return IChange[]
82 | */
83 | public function getChanges(): array {
84 | if ($this->fd === null) {
85 | return [];
86 | }
87 | stream_set_blocking($this->fd, false);
88 | return $this->deduplicateEvents($this->readEvents());
89 | }
90 |
91 | /**
92 | * @return IChange[]
93 | */
94 | private function readEvents(): array {
95 | if ($this->fd === null) {
96 | return [];
97 | }
98 | $events = inotify_read($this->fd);
99 | $parsedEvents = array_map([$this, 'parseEvent'], $events);
100 | return $this->deduplicateEvents(call_user_func_array('array_merge', $parsedEvents));
101 | }
102 |
103 | /**
104 | * @param IChange[] $events
105 | * @return IChange[]
106 | */
107 | private function deduplicateEvents(array $events): array {
108 | /** @var null|IChange $lastEvent */
109 | $lastEvent = null;
110 | $filteredEvents = [];
111 |
112 | foreach ($events as $event) {
113 | if ($lastEvent === null || ($event->getPath() !== $lastEvent->getPath() && $event->getType() == $event->getType())) {
114 | $filteredEvents[] = $event;
115 | }
116 | $lastEvent = $event;
117 | }
118 |
119 | return $filteredEvents;
120 | }
121 |
122 | /**
123 | * @param array $event
124 | * @return IChange[]
125 | * @throws \Exception
126 | */
127 | private function parseEvent(array $event): array {
128 | if (!isset($this->pathMap[$event['wd']])) {
129 | throw new \Exception('Invalid inotify event');
130 | }
131 | $path = $this->pathMap[$event['wd']] . '/' . $event['name'];
132 |
133 | $mask = $event['mask'];
134 | $cookie = $event['cookie'];
135 | if (($mask & \IN_MOVED_TO) || ($mask & \IN_MOVED_FROM)) {
136 | if (!isset($this->moveMap[$cookie])) {
137 | $this->moveMap[$cookie] = [];
138 | }
139 | }
140 | if ($mask & \IN_MOVED_FROM) {
141 | if (isset($this->moveMap[$cookie]['to'])) {
142 | $targetPath = $this->moveMap[$event['cookie']]['to'];
143 | unset($this->moveMap[$cookie]);
144 | return [
145 | new RenameChange(IChange::RENAMED, $this->getRelativePath($path),
146 | $this->getRelativePath($targetPath)),
147 | ];
148 | } else {
149 | $this->moveMap[$event['cookie']]['from'] = $path;
150 | return [];
151 | }
152 | }
153 |
154 | if ($mask & \IN_MOVED_TO) {
155 | if (isset($this->moveMap[$cookie]['from'])) {
156 | $fromPath = $this->moveMap[$event['cookie']]['from'];
157 | unset($this->moveMap[$cookie]);
158 | return [
159 | new RenameChange(IChange::RENAMED, $this->getRelativePath($fromPath),
160 | $this->getRelativePath($path)),
161 | ];
162 | } else {
163 | $this->moveMap[$event['cookie']]['to'] = $path;
164 | return [];
165 | }
166 | }
167 |
168 | if ($mask & \IN_MODIFY) {
169 | return [new Change(IChange::MODIFIED, $this->getRelativePath($path))];
170 | }
171 | if ($mask & \IN_CREATE) {
172 | if (is_dir($path . '/')) {
173 | $events = $this->createChildEvents($path);
174 | $this->watchPath($path);
175 | } else {
176 | $events = [];
177 | }
178 | array_unshift($events, new Change(IChange::ADDED, $this->getRelativePath($path)));
179 | return $events;
180 | }
181 | if ($mask & \IN_DELETE) {
182 | return [new Change(IChange::REMOVED, $this->getRelativePath($path))];
183 | }
184 | return [];
185 | }
186 |
187 | /**
188 | * create "create changes" for files inside a newly detected directory
189 | *
190 | * this is needed since a file can be added to a directory before we have the time to add a watch
191 | *
192 | * @param $path
193 | * @return IChange[]
194 | */
195 | private function createChildEvents(string $path): array {
196 | $changes = [];
197 | foreach ($this->getDirectoryIterator($path) as $file) {
198 | $changes[] = new Change(IChange::ADDED, $this->getRelativePath($file));
199 | }
200 | return $changes;
201 | }
202 |
203 | /**
204 | * @param $path
205 | * @return string
206 | */
207 | private function getRelativePath(string $path): string {
208 | return substr($path, strlen($this->basePath) + 1) ?: '';
209 | }
210 |
211 | public function listen(callable $callback): void {
212 | if ($this->fd === null) {
213 | return;
214 | }
215 | stream_set_blocking($this->fd, true);
216 | if (function_exists('pcntl_signal')) {
217 | pcntl_signal(SIGTERM, [$this, 'stop']);
218 | pcntl_signal(SIGINT, [$this, 'stop']);
219 | }
220 | $active = true;
221 | // loop while $this->fd is valid
222 | while ($active && is_resource($this->fd)) {
223 | $read = [$this->fd];
224 | $write = null;
225 | $except = null;
226 | // suppress errors and warnings (use return value instead)
227 | $changed = @stream_select($read, $write, $except, 60);
228 | // php docs say: On error FALSE is returned and a warning raised
229 | // php docs say: (this can happen if the system call is interrupted by an incoming signal).
230 | // handle those signals if possible
231 | if ($changed === false && function_exists('pcntl_signal_dispatch')) {
232 | pcntl_signal_dispatch();
233 | }
234 |
235 | // we only added one stream, so $changed > 0 means it is readable now
236 | if ($changed) {
237 | $events = $this->readEvents();
238 | foreach ($events as $event) {
239 | if ($callback($event) === false) {
240 | $active = false; // stop this loop
241 | }
242 | }
243 | }
244 | }
245 | }
246 |
247 | public function stop(): void {
248 | if ($this->fd === null) {
249 | return;
250 | }
251 | $handle = $this->fd;
252 | $this->fd = null;
253 | fclose($handle);
254 | }
255 | }
256 |
--------------------------------------------------------------------------------
/psalm.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/Storage/NotifyHandlerTest.php:
--------------------------------------------------------------------------------
1 |
5 | *
6 | * @license GNU AGPL version 3 or any later version
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as
10 | * published by the Free Software Foundation, either version 3 of the
11 | * License, or (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | *
21 | */
22 |
23 | namespace OCA\Files_INotify\Tests\Storage;
24 |
25 | use OC\Files\Notify\Change;
26 | use OC\Files\Notify\RenameChange;
27 | use OCA\Files_INotify\Storage\NotifyHandler;
28 | use OCP\Files\Notify\IChange;
29 | use Test\TestCase;
30 |
31 | class NotifyHandlerTest extends TestCase {
32 | /** @var NotifyHandler */
33 | private $handler;
34 | /** @var string */
35 | private $basePath;
36 |
37 | protected function setUp(): void {
38 | parent::setUp();
39 |
40 | $this->basePath = \OC::$server->getTempManager()->getTemporaryFolder();
41 | $this->handler = new NotifyHandler($this->basePath);
42 | }
43 |
44 | public function testBasicNotify() {
45 | file_put_contents($this->basePath . 'foo.txt', 'foo');
46 | usleep(100 * 1000);
47 |
48 | $changes = $this->handler->getChanges();
49 | $this->assertEquals([new Change(IChange::ADDED, 'foo.txt')], $changes);
50 |
51 | file_put_contents($this->basePath . 'foo.txt', 'bar');
52 | usleep(100 * 1000);
53 |
54 | $changes = $this->handler->getChanges();
55 | $this->assertEquals([new Change(IChange::MODIFIED, 'foo.txt')], $changes);
56 |
57 | rename($this->basePath . 'foo.txt', $this->basePath . 'bar.txt');
58 | usleep(100 * 1000);
59 |
60 | $changes = $this->handler->getChanges();
61 | $this->assertEquals([new RenameChange(IChange::RENAMED, 'foo.txt', 'bar.txt')], $changes);
62 |
63 | unlink($this->basePath . 'bar.txt');
64 | usleep(100 * 1000);
65 |
66 | $changes = $this->handler->getChanges();
67 | $this->assertEquals([new Change(IChange::REMOVED, 'bar.txt')], $changes);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | addPsr4('Test\\', OC::$SERVERROOT . '/tests/lib/', true);
8 | \OC::$composerAutoloader->addPsr4('Tests\\', OC::$SERVERROOT . '/tests/', true);
9 |
10 | OC_App::loadApp('files_inotify');
11 |
12 | OC_Hook::clear();
13 |
--------------------------------------------------------------------------------
/tests/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 | .
9 |
10 |
11 |
12 | ../
13 |
14 | ../tests
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/tests/stub.phpstub:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * @license GNU AGPL version 3 or any later version
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as
11 | * published by the Free Software Foundation, either version 3 of the
12 | * License, or (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | *
22 | */
23 |
24 | namespace {
25 | class OC {
26 | static $CLI = false;
27 | }
28 | }
29 |
30 | namespace OC\Files\Notify {
31 |
32 | use OCP\Files\Notify\IChange;
33 | use OCP\Files\Notify\IRenameChange;
34 |
35 | class Change implements IChange {
36 | public function __construct(int $type, string $path) {
37 | }
38 |
39 | public function getType() {
40 | }
41 |
42 | public function getPath() {
43 | }
44 |
45 | }
46 |
47 | class RenameChange implements IRenameChange, IChange {
48 | public function __construct(int $type, string $source, string $target) {
49 | }
50 |
51 | public function getType() {
52 | }
53 |
54 | public function getPath() {
55 | }
56 |
57 | public function getTargetPath() {
58 | }
59 | }
60 | }
61 |
62 | namespace OCA\Files_External\Lib\Backend {
63 | class Backend {
64 | /**
65 | * @param string $class
66 | * @return $this
67 | */
68 | public function setStorageClass($class) {
69 |
70 | }
71 | }
72 |
73 | class Local extends Backend {
74 |
75 | public function __construct($l10n, $auth) {
76 | }
77 | }
78 | }
79 |
80 | namespace OCA\Files_External\Lib\Auth {
81 | class NullMechanism {
82 | }
83 | }
84 |
85 | namespace OCA\Files_External\Lib\Config {
86 | use OCA\Files_External\Lib\Backend\Backend;
87 |
88 | interface IBackendProvider {
89 | /**
90 | * @return Backend[]
91 | */
92 | public function getBackends();
93 | }
94 | }
95 |
96 | namespace OCA\Files_External\Service {
97 |
98 | use OCA\Files_External\Lib\Config\IBackendProvider;
99 |
100 | class BackendService {
101 | public function registerBackendProvider(IBackendProvider $provider) {
102 |
103 | }
104 | }
105 | }
106 |
107 | namespace OC\Files\Storage {
108 | class Local {
109 | public $datadir;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/vendor-bin/cs-fixer/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "require-dev": {
3 | "nextcloud/coding-standard": "^1.3.1"
4 | },
5 | "config": {
6 | "platform": {
7 | "php": "8.1"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/vendor-bin/cs-fixer/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "b80be9f75e57093d11f0a5065039b255",
8 | "packages": [],
9 | "packages-dev": [
10 | {
11 | "name": "kubawerlos/php-cs-fixer-custom-fixers",
12 | "version": "v3.23.0",
13 | "source": {
14 | "type": "git",
15 | "url": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers.git",
16 | "reference": "b3210c6e546bdfc95664297a8971ae3b6b1f4a5a"
17 | },
18 | "dist": {
19 | "type": "zip",
20 | "url": "https://api.github.com/repos/kubawerlos/php-cs-fixer-custom-fixers/zipball/b3210c6e546bdfc95664297a8971ae3b6b1f4a5a",
21 | "reference": "b3210c6e546bdfc95664297a8971ae3b6b1f4a5a",
22 | "shasum": ""
23 | },
24 | "require": {
25 | "ext-filter": "*",
26 | "ext-tokenizer": "*",
27 | "friendsofphp/php-cs-fixer": "^3.61.1",
28 | "php": "^7.4 || ^8.0"
29 | },
30 | "require-dev": {
31 | "phpunit/phpunit": "^9.6.4 || ^10.5.29"
32 | },
33 | "type": "library",
34 | "autoload": {
35 | "psr-4": {
36 | "PhpCsFixerCustomFixers\\": "src"
37 | }
38 | },
39 | "notification-url": "https://packagist.org/downloads/",
40 | "license": [
41 | "MIT"
42 | ],
43 | "authors": [
44 | {
45 | "name": "Kuba Werłos",
46 | "email": "werlos@gmail.com"
47 | }
48 | ],
49 | "description": "A set of custom fixers for PHP CS Fixer",
50 | "support": {
51 | "issues": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/issues",
52 | "source": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/tree/v3.23.0"
53 | },
54 | "time": "2025-02-15T09:15:56+00:00"
55 | },
56 | {
57 | "name": "nextcloud/coding-standard",
58 | "version": "v1.3.2",
59 | "source": {
60 | "type": "git",
61 | "url": "https://github.com/nextcloud/coding-standard.git",
62 | "reference": "9c719c4747fa26efc12f2e8b21c14a9a75c6ba6d"
63 | },
64 | "dist": {
65 | "type": "zip",
66 | "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/9c719c4747fa26efc12f2e8b21c14a9a75c6ba6d",
67 | "reference": "9c719c4747fa26efc12f2e8b21c14a9a75c6ba6d",
68 | "shasum": ""
69 | },
70 | "require": {
71 | "kubawerlos/php-cs-fixer-custom-fixers": "^3.22",
72 | "php": "^7.3|^8.0",
73 | "php-cs-fixer/shim": "^3.17"
74 | },
75 | "type": "library",
76 | "autoload": {
77 | "psr-4": {
78 | "Nextcloud\\CodingStandard\\": "src"
79 | }
80 | },
81 | "notification-url": "https://packagist.org/downloads/",
82 | "license": [
83 | "MIT"
84 | ],
85 | "authors": [
86 | {
87 | "name": "Christoph Wurst",
88 | "email": "christoph@winzerhof-wurst.at"
89 | }
90 | ],
91 | "description": "Nextcloud coding standards for the php cs fixer",
92 | "support": {
93 | "issues": "https://github.com/nextcloud/coding-standard/issues",
94 | "source": "https://github.com/nextcloud/coding-standard/tree/v1.3.2"
95 | },
96 | "time": "2024-10-14T16:49:05+00:00"
97 | },
98 | {
99 | "name": "php-cs-fixer/shim",
100 | "version": "v3.71.0",
101 | "source": {
102 | "type": "git",
103 | "url": "https://github.com/PHP-CS-Fixer/shim.git",
104 | "reference": "bbc2a38cc7b89727def47025dd8e03e1e3e46d82"
105 | },
106 | "dist": {
107 | "type": "zip",
108 | "url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/bbc2a38cc7b89727def47025dd8e03e1e3e46d82",
109 | "reference": "bbc2a38cc7b89727def47025dd8e03e1e3e46d82",
110 | "shasum": ""
111 | },
112 | "require": {
113 | "ext-json": "*",
114 | "ext-tokenizer": "*",
115 | "php": "^7.4 || ^8.0"
116 | },
117 | "replace": {
118 | "friendsofphp/php-cs-fixer": "self.version"
119 | },
120 | "suggest": {
121 | "ext-dom": "For handling output formats in XML",
122 | "ext-mbstring": "For handling non-UTF8 characters."
123 | },
124 | "bin": [
125 | "php-cs-fixer",
126 | "php-cs-fixer.phar"
127 | ],
128 | "type": "application",
129 | "notification-url": "https://packagist.org/downloads/",
130 | "license": [
131 | "MIT"
132 | ],
133 | "authors": [
134 | {
135 | "name": "Fabien Potencier",
136 | "email": "fabien@symfony.com"
137 | },
138 | {
139 | "name": "Dariusz Rumiński",
140 | "email": "dariusz.ruminski@gmail.com"
141 | }
142 | ],
143 | "description": "A tool to automatically fix PHP code style",
144 | "support": {
145 | "issues": "https://github.com/PHP-CS-Fixer/shim/issues",
146 | "source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.71.0"
147 | },
148 | "time": "2025-03-07T23:07:16+00:00"
149 | }
150 | ],
151 | "aliases": [],
152 | "minimum-stability": "stable",
153 | "stability-flags": {},
154 | "prefer-stable": false,
155 | "prefer-lowest": false,
156 | "platform": {},
157 | "platform-dev": {},
158 | "platform-overrides": {
159 | "php": "8.1"
160 | },
161 | "plugin-api-version": "2.6.0"
162 | }
163 |
--------------------------------------------------------------------------------
/vendor-bin/phpunit/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "require-dev": {
3 | "phpunit/phpunit": "^9"
4 | },
5 | "config": {
6 | "platform": {
7 | "php": "8.1"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/vendor-bin/phpunit/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "d31767cd369c343e7e8721f89b76a7f4",
8 | "packages": [],
9 | "packages-dev": [
10 | {
11 | "name": "doctrine/instantiator",
12 | "version": "2.0.0",
13 | "source": {
14 | "type": "git",
15 | "url": "https://github.com/doctrine/instantiator.git",
16 | "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0"
17 | },
18 | "dist": {
19 | "type": "zip",
20 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
21 | "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
22 | "shasum": ""
23 | },
24 | "require": {
25 | "php": "^8.1"
26 | },
27 | "require-dev": {
28 | "doctrine/coding-standard": "^11",
29 | "ext-pdo": "*",
30 | "ext-phar": "*",
31 | "phpbench/phpbench": "^1.2",
32 | "phpstan/phpstan": "^1.9.4",
33 | "phpstan/phpstan-phpunit": "^1.3",
34 | "phpunit/phpunit": "^9.5.27",
35 | "vimeo/psalm": "^5.4"
36 | },
37 | "type": "library",
38 | "autoload": {
39 | "psr-4": {
40 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
41 | }
42 | },
43 | "notification-url": "https://packagist.org/downloads/",
44 | "license": [
45 | "MIT"
46 | ],
47 | "authors": [
48 | {
49 | "name": "Marco Pivetta",
50 | "email": "ocramius@gmail.com",
51 | "homepage": "https://ocramius.github.io/"
52 | }
53 | ],
54 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
55 | "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
56 | "keywords": [
57 | "constructor",
58 | "instantiate"
59 | ],
60 | "support": {
61 | "issues": "https://github.com/doctrine/instantiator/issues",
62 | "source": "https://github.com/doctrine/instantiator/tree/2.0.0"
63 | },
64 | "funding": [
65 | {
66 | "url": "https://www.doctrine-project.org/sponsorship.html",
67 | "type": "custom"
68 | },
69 | {
70 | "url": "https://www.patreon.com/phpdoctrine",
71 | "type": "patreon"
72 | },
73 | {
74 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
75 | "type": "tidelift"
76 | }
77 | ],
78 | "time": "2022-12-30T00:23:10+00:00"
79 | },
80 | {
81 | "name": "myclabs/deep-copy",
82 | "version": "1.13.0",
83 | "source": {
84 | "type": "git",
85 | "url": "https://github.com/myclabs/DeepCopy.git",
86 | "reference": "024473a478be9df5fdaca2c793f2232fe788e414"
87 | },
88 | "dist": {
89 | "type": "zip",
90 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414",
91 | "reference": "024473a478be9df5fdaca2c793f2232fe788e414",
92 | "shasum": ""
93 | },
94 | "require": {
95 | "php": "^7.1 || ^8.0"
96 | },
97 | "conflict": {
98 | "doctrine/collections": "<1.6.8",
99 | "doctrine/common": "<2.13.3 || >=3 <3.2.2"
100 | },
101 | "require-dev": {
102 | "doctrine/collections": "^1.6.8",
103 | "doctrine/common": "^2.13.3 || ^3.2.2",
104 | "phpspec/prophecy": "^1.10",
105 | "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
106 | },
107 | "type": "library",
108 | "autoload": {
109 | "files": [
110 | "src/DeepCopy/deep_copy.php"
111 | ],
112 | "psr-4": {
113 | "DeepCopy\\": "src/DeepCopy/"
114 | }
115 | },
116 | "notification-url": "https://packagist.org/downloads/",
117 | "license": [
118 | "MIT"
119 | ],
120 | "description": "Create deep copies (clones) of your objects",
121 | "keywords": [
122 | "clone",
123 | "copy",
124 | "duplicate",
125 | "object",
126 | "object graph"
127 | ],
128 | "support": {
129 | "issues": "https://github.com/myclabs/DeepCopy/issues",
130 | "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0"
131 | },
132 | "funding": [
133 | {
134 | "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
135 | "type": "tidelift"
136 | }
137 | ],
138 | "time": "2025-02-12T12:17:51+00:00"
139 | },
140 | {
141 | "name": "nikic/php-parser",
142 | "version": "v5.4.0",
143 | "source": {
144 | "type": "git",
145 | "url": "https://github.com/nikic/PHP-Parser.git",
146 | "reference": "447a020a1f875a434d62f2a401f53b82a396e494"
147 | },
148 | "dist": {
149 | "type": "zip",
150 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494",
151 | "reference": "447a020a1f875a434d62f2a401f53b82a396e494",
152 | "shasum": ""
153 | },
154 | "require": {
155 | "ext-ctype": "*",
156 | "ext-json": "*",
157 | "ext-tokenizer": "*",
158 | "php": ">=7.4"
159 | },
160 | "require-dev": {
161 | "ircmaxell/php-yacc": "^0.0.7",
162 | "phpunit/phpunit": "^9.0"
163 | },
164 | "bin": [
165 | "bin/php-parse"
166 | ],
167 | "type": "library",
168 | "extra": {
169 | "branch-alias": {
170 | "dev-master": "5.0-dev"
171 | }
172 | },
173 | "autoload": {
174 | "psr-4": {
175 | "PhpParser\\": "lib/PhpParser"
176 | }
177 | },
178 | "notification-url": "https://packagist.org/downloads/",
179 | "license": [
180 | "BSD-3-Clause"
181 | ],
182 | "authors": [
183 | {
184 | "name": "Nikita Popov"
185 | }
186 | ],
187 | "description": "A PHP parser written in PHP",
188 | "keywords": [
189 | "parser",
190 | "php"
191 | ],
192 | "support": {
193 | "issues": "https://github.com/nikic/PHP-Parser/issues",
194 | "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0"
195 | },
196 | "time": "2024-12-30T11:07:19+00:00"
197 | },
198 | {
199 | "name": "phar-io/manifest",
200 | "version": "2.0.4",
201 | "source": {
202 | "type": "git",
203 | "url": "https://github.com/phar-io/manifest.git",
204 | "reference": "54750ef60c58e43759730615a392c31c80e23176"
205 | },
206 | "dist": {
207 | "type": "zip",
208 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
209 | "reference": "54750ef60c58e43759730615a392c31c80e23176",
210 | "shasum": ""
211 | },
212 | "require": {
213 | "ext-dom": "*",
214 | "ext-libxml": "*",
215 | "ext-phar": "*",
216 | "ext-xmlwriter": "*",
217 | "phar-io/version": "^3.0.1",
218 | "php": "^7.2 || ^8.0"
219 | },
220 | "type": "library",
221 | "extra": {
222 | "branch-alias": {
223 | "dev-master": "2.0.x-dev"
224 | }
225 | },
226 | "autoload": {
227 | "classmap": [
228 | "src/"
229 | ]
230 | },
231 | "notification-url": "https://packagist.org/downloads/",
232 | "license": [
233 | "BSD-3-Clause"
234 | ],
235 | "authors": [
236 | {
237 | "name": "Arne Blankerts",
238 | "email": "arne@blankerts.de",
239 | "role": "Developer"
240 | },
241 | {
242 | "name": "Sebastian Heuer",
243 | "email": "sebastian@phpeople.de",
244 | "role": "Developer"
245 | },
246 | {
247 | "name": "Sebastian Bergmann",
248 | "email": "sebastian@phpunit.de",
249 | "role": "Developer"
250 | }
251 | ],
252 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
253 | "support": {
254 | "issues": "https://github.com/phar-io/manifest/issues",
255 | "source": "https://github.com/phar-io/manifest/tree/2.0.4"
256 | },
257 | "funding": [
258 | {
259 | "url": "https://github.com/theseer",
260 | "type": "github"
261 | }
262 | ],
263 | "time": "2024-03-03T12:33:53+00:00"
264 | },
265 | {
266 | "name": "phar-io/version",
267 | "version": "3.2.1",
268 | "source": {
269 | "type": "git",
270 | "url": "https://github.com/phar-io/version.git",
271 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
272 | },
273 | "dist": {
274 | "type": "zip",
275 | "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
276 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
277 | "shasum": ""
278 | },
279 | "require": {
280 | "php": "^7.2 || ^8.0"
281 | },
282 | "type": "library",
283 | "autoload": {
284 | "classmap": [
285 | "src/"
286 | ]
287 | },
288 | "notification-url": "https://packagist.org/downloads/",
289 | "license": [
290 | "BSD-3-Clause"
291 | ],
292 | "authors": [
293 | {
294 | "name": "Arne Blankerts",
295 | "email": "arne@blankerts.de",
296 | "role": "Developer"
297 | },
298 | {
299 | "name": "Sebastian Heuer",
300 | "email": "sebastian@phpeople.de",
301 | "role": "Developer"
302 | },
303 | {
304 | "name": "Sebastian Bergmann",
305 | "email": "sebastian@phpunit.de",
306 | "role": "Developer"
307 | }
308 | ],
309 | "description": "Library for handling version information and constraints",
310 | "support": {
311 | "issues": "https://github.com/phar-io/version/issues",
312 | "source": "https://github.com/phar-io/version/tree/3.2.1"
313 | },
314 | "time": "2022-02-21T01:04:05+00:00"
315 | },
316 | {
317 | "name": "phpunit/php-code-coverage",
318 | "version": "9.2.32",
319 | "source": {
320 | "type": "git",
321 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
322 | "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5"
323 | },
324 | "dist": {
325 | "type": "zip",
326 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5",
327 | "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5",
328 | "shasum": ""
329 | },
330 | "require": {
331 | "ext-dom": "*",
332 | "ext-libxml": "*",
333 | "ext-xmlwriter": "*",
334 | "nikic/php-parser": "^4.19.1 || ^5.1.0",
335 | "php": ">=7.3",
336 | "phpunit/php-file-iterator": "^3.0.6",
337 | "phpunit/php-text-template": "^2.0.4",
338 | "sebastian/code-unit-reverse-lookup": "^2.0.3",
339 | "sebastian/complexity": "^2.0.3",
340 | "sebastian/environment": "^5.1.5",
341 | "sebastian/lines-of-code": "^1.0.4",
342 | "sebastian/version": "^3.0.2",
343 | "theseer/tokenizer": "^1.2.3"
344 | },
345 | "require-dev": {
346 | "phpunit/phpunit": "^9.6"
347 | },
348 | "suggest": {
349 | "ext-pcov": "PHP extension that provides line coverage",
350 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
351 | },
352 | "type": "library",
353 | "extra": {
354 | "branch-alias": {
355 | "dev-main": "9.2.x-dev"
356 | }
357 | },
358 | "autoload": {
359 | "classmap": [
360 | "src/"
361 | ]
362 | },
363 | "notification-url": "https://packagist.org/downloads/",
364 | "license": [
365 | "BSD-3-Clause"
366 | ],
367 | "authors": [
368 | {
369 | "name": "Sebastian Bergmann",
370 | "email": "sebastian@phpunit.de",
371 | "role": "lead"
372 | }
373 | ],
374 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
375 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
376 | "keywords": [
377 | "coverage",
378 | "testing",
379 | "xunit"
380 | ],
381 | "support": {
382 | "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
383 | "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
384 | "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32"
385 | },
386 | "funding": [
387 | {
388 | "url": "https://github.com/sebastianbergmann",
389 | "type": "github"
390 | }
391 | ],
392 | "time": "2024-08-22T04:23:01+00:00"
393 | },
394 | {
395 | "name": "phpunit/php-file-iterator",
396 | "version": "3.0.6",
397 | "source": {
398 | "type": "git",
399 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
400 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf"
401 | },
402 | "dist": {
403 | "type": "zip",
404 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
405 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
406 | "shasum": ""
407 | },
408 | "require": {
409 | "php": ">=7.3"
410 | },
411 | "require-dev": {
412 | "phpunit/phpunit": "^9.3"
413 | },
414 | "type": "library",
415 | "extra": {
416 | "branch-alias": {
417 | "dev-master": "3.0-dev"
418 | }
419 | },
420 | "autoload": {
421 | "classmap": [
422 | "src/"
423 | ]
424 | },
425 | "notification-url": "https://packagist.org/downloads/",
426 | "license": [
427 | "BSD-3-Clause"
428 | ],
429 | "authors": [
430 | {
431 | "name": "Sebastian Bergmann",
432 | "email": "sebastian@phpunit.de",
433 | "role": "lead"
434 | }
435 | ],
436 | "description": "FilterIterator implementation that filters files based on a list of suffixes.",
437 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
438 | "keywords": [
439 | "filesystem",
440 | "iterator"
441 | ],
442 | "support": {
443 | "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
444 | "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6"
445 | },
446 | "funding": [
447 | {
448 | "url": "https://github.com/sebastianbergmann",
449 | "type": "github"
450 | }
451 | ],
452 | "time": "2021-12-02T12:48:52+00:00"
453 | },
454 | {
455 | "name": "phpunit/php-invoker",
456 | "version": "3.1.1",
457 | "source": {
458 | "type": "git",
459 | "url": "https://github.com/sebastianbergmann/php-invoker.git",
460 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67"
461 | },
462 | "dist": {
463 | "type": "zip",
464 | "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
465 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
466 | "shasum": ""
467 | },
468 | "require": {
469 | "php": ">=7.3"
470 | },
471 | "require-dev": {
472 | "ext-pcntl": "*",
473 | "phpunit/phpunit": "^9.3"
474 | },
475 | "suggest": {
476 | "ext-pcntl": "*"
477 | },
478 | "type": "library",
479 | "extra": {
480 | "branch-alias": {
481 | "dev-master": "3.1-dev"
482 | }
483 | },
484 | "autoload": {
485 | "classmap": [
486 | "src/"
487 | ]
488 | },
489 | "notification-url": "https://packagist.org/downloads/",
490 | "license": [
491 | "BSD-3-Clause"
492 | ],
493 | "authors": [
494 | {
495 | "name": "Sebastian Bergmann",
496 | "email": "sebastian@phpunit.de",
497 | "role": "lead"
498 | }
499 | ],
500 | "description": "Invoke callables with a timeout",
501 | "homepage": "https://github.com/sebastianbergmann/php-invoker/",
502 | "keywords": [
503 | "process"
504 | ],
505 | "support": {
506 | "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
507 | "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1"
508 | },
509 | "funding": [
510 | {
511 | "url": "https://github.com/sebastianbergmann",
512 | "type": "github"
513 | }
514 | ],
515 | "time": "2020-09-28T05:58:55+00:00"
516 | },
517 | {
518 | "name": "phpunit/php-text-template",
519 | "version": "2.0.4",
520 | "source": {
521 | "type": "git",
522 | "url": "https://github.com/sebastianbergmann/php-text-template.git",
523 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28"
524 | },
525 | "dist": {
526 | "type": "zip",
527 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
528 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
529 | "shasum": ""
530 | },
531 | "require": {
532 | "php": ">=7.3"
533 | },
534 | "require-dev": {
535 | "phpunit/phpunit": "^9.3"
536 | },
537 | "type": "library",
538 | "extra": {
539 | "branch-alias": {
540 | "dev-master": "2.0-dev"
541 | }
542 | },
543 | "autoload": {
544 | "classmap": [
545 | "src/"
546 | ]
547 | },
548 | "notification-url": "https://packagist.org/downloads/",
549 | "license": [
550 | "BSD-3-Clause"
551 | ],
552 | "authors": [
553 | {
554 | "name": "Sebastian Bergmann",
555 | "email": "sebastian@phpunit.de",
556 | "role": "lead"
557 | }
558 | ],
559 | "description": "Simple template engine.",
560 | "homepage": "https://github.com/sebastianbergmann/php-text-template/",
561 | "keywords": [
562 | "template"
563 | ],
564 | "support": {
565 | "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
566 | "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4"
567 | },
568 | "funding": [
569 | {
570 | "url": "https://github.com/sebastianbergmann",
571 | "type": "github"
572 | }
573 | ],
574 | "time": "2020-10-26T05:33:50+00:00"
575 | },
576 | {
577 | "name": "phpunit/php-timer",
578 | "version": "5.0.3",
579 | "source": {
580 | "type": "git",
581 | "url": "https://github.com/sebastianbergmann/php-timer.git",
582 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2"
583 | },
584 | "dist": {
585 | "type": "zip",
586 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
587 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
588 | "shasum": ""
589 | },
590 | "require": {
591 | "php": ">=7.3"
592 | },
593 | "require-dev": {
594 | "phpunit/phpunit": "^9.3"
595 | },
596 | "type": "library",
597 | "extra": {
598 | "branch-alias": {
599 | "dev-master": "5.0-dev"
600 | }
601 | },
602 | "autoload": {
603 | "classmap": [
604 | "src/"
605 | ]
606 | },
607 | "notification-url": "https://packagist.org/downloads/",
608 | "license": [
609 | "BSD-3-Clause"
610 | ],
611 | "authors": [
612 | {
613 | "name": "Sebastian Bergmann",
614 | "email": "sebastian@phpunit.de",
615 | "role": "lead"
616 | }
617 | ],
618 | "description": "Utility class for timing",
619 | "homepage": "https://github.com/sebastianbergmann/php-timer/",
620 | "keywords": [
621 | "timer"
622 | ],
623 | "support": {
624 | "issues": "https://github.com/sebastianbergmann/php-timer/issues",
625 | "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3"
626 | },
627 | "funding": [
628 | {
629 | "url": "https://github.com/sebastianbergmann",
630 | "type": "github"
631 | }
632 | ],
633 | "time": "2020-10-26T13:16:10+00:00"
634 | },
635 | {
636 | "name": "phpunit/phpunit",
637 | "version": "9.6.22",
638 | "source": {
639 | "type": "git",
640 | "url": "https://github.com/sebastianbergmann/phpunit.git",
641 | "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c"
642 | },
643 | "dist": {
644 | "type": "zip",
645 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f80235cb4d3caa59ae09be3adf1ded27521d1a9c",
646 | "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c",
647 | "shasum": ""
648 | },
649 | "require": {
650 | "doctrine/instantiator": "^1.5.0 || ^2",
651 | "ext-dom": "*",
652 | "ext-json": "*",
653 | "ext-libxml": "*",
654 | "ext-mbstring": "*",
655 | "ext-xml": "*",
656 | "ext-xmlwriter": "*",
657 | "myclabs/deep-copy": "^1.12.1",
658 | "phar-io/manifest": "^2.0.4",
659 | "phar-io/version": "^3.2.1",
660 | "php": ">=7.3",
661 | "phpunit/php-code-coverage": "^9.2.32",
662 | "phpunit/php-file-iterator": "^3.0.6",
663 | "phpunit/php-invoker": "^3.1.1",
664 | "phpunit/php-text-template": "^2.0.4",
665 | "phpunit/php-timer": "^5.0.3",
666 | "sebastian/cli-parser": "^1.0.2",
667 | "sebastian/code-unit": "^1.0.8",
668 | "sebastian/comparator": "^4.0.8",
669 | "sebastian/diff": "^4.0.6",
670 | "sebastian/environment": "^5.1.5",
671 | "sebastian/exporter": "^4.0.6",
672 | "sebastian/global-state": "^5.0.7",
673 | "sebastian/object-enumerator": "^4.0.4",
674 | "sebastian/resource-operations": "^3.0.4",
675 | "sebastian/type": "^3.2.1",
676 | "sebastian/version": "^3.0.2"
677 | },
678 | "suggest": {
679 | "ext-soap": "To be able to generate mocks based on WSDL files",
680 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
681 | },
682 | "bin": [
683 | "phpunit"
684 | ],
685 | "type": "library",
686 | "extra": {
687 | "branch-alias": {
688 | "dev-master": "9.6-dev"
689 | }
690 | },
691 | "autoload": {
692 | "files": [
693 | "src/Framework/Assert/Functions.php"
694 | ],
695 | "classmap": [
696 | "src/"
697 | ]
698 | },
699 | "notification-url": "https://packagist.org/downloads/",
700 | "license": [
701 | "BSD-3-Clause"
702 | ],
703 | "authors": [
704 | {
705 | "name": "Sebastian Bergmann",
706 | "email": "sebastian@phpunit.de",
707 | "role": "lead"
708 | }
709 | ],
710 | "description": "The PHP Unit Testing framework.",
711 | "homepage": "https://phpunit.de/",
712 | "keywords": [
713 | "phpunit",
714 | "testing",
715 | "xunit"
716 | ],
717 | "support": {
718 | "issues": "https://github.com/sebastianbergmann/phpunit/issues",
719 | "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
720 | "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.22"
721 | },
722 | "funding": [
723 | {
724 | "url": "https://phpunit.de/sponsors.html",
725 | "type": "custom"
726 | },
727 | {
728 | "url": "https://github.com/sebastianbergmann",
729 | "type": "github"
730 | },
731 | {
732 | "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
733 | "type": "tidelift"
734 | }
735 | ],
736 | "time": "2024-12-05T13:48:26+00:00"
737 | },
738 | {
739 | "name": "sebastian/cli-parser",
740 | "version": "1.0.2",
741 | "source": {
742 | "type": "git",
743 | "url": "https://github.com/sebastianbergmann/cli-parser.git",
744 | "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b"
745 | },
746 | "dist": {
747 | "type": "zip",
748 | "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
749 | "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
750 | "shasum": ""
751 | },
752 | "require": {
753 | "php": ">=7.3"
754 | },
755 | "require-dev": {
756 | "phpunit/phpunit": "^9.3"
757 | },
758 | "type": "library",
759 | "extra": {
760 | "branch-alias": {
761 | "dev-master": "1.0-dev"
762 | }
763 | },
764 | "autoload": {
765 | "classmap": [
766 | "src/"
767 | ]
768 | },
769 | "notification-url": "https://packagist.org/downloads/",
770 | "license": [
771 | "BSD-3-Clause"
772 | ],
773 | "authors": [
774 | {
775 | "name": "Sebastian Bergmann",
776 | "email": "sebastian@phpunit.de",
777 | "role": "lead"
778 | }
779 | ],
780 | "description": "Library for parsing CLI options",
781 | "homepage": "https://github.com/sebastianbergmann/cli-parser",
782 | "support": {
783 | "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
784 | "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2"
785 | },
786 | "funding": [
787 | {
788 | "url": "https://github.com/sebastianbergmann",
789 | "type": "github"
790 | }
791 | ],
792 | "time": "2024-03-02T06:27:43+00:00"
793 | },
794 | {
795 | "name": "sebastian/code-unit",
796 | "version": "1.0.8",
797 | "source": {
798 | "type": "git",
799 | "url": "https://github.com/sebastianbergmann/code-unit.git",
800 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120"
801 | },
802 | "dist": {
803 | "type": "zip",
804 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120",
805 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120",
806 | "shasum": ""
807 | },
808 | "require": {
809 | "php": ">=7.3"
810 | },
811 | "require-dev": {
812 | "phpunit/phpunit": "^9.3"
813 | },
814 | "type": "library",
815 | "extra": {
816 | "branch-alias": {
817 | "dev-master": "1.0-dev"
818 | }
819 | },
820 | "autoload": {
821 | "classmap": [
822 | "src/"
823 | ]
824 | },
825 | "notification-url": "https://packagist.org/downloads/",
826 | "license": [
827 | "BSD-3-Clause"
828 | ],
829 | "authors": [
830 | {
831 | "name": "Sebastian Bergmann",
832 | "email": "sebastian@phpunit.de",
833 | "role": "lead"
834 | }
835 | ],
836 | "description": "Collection of value objects that represent the PHP code units",
837 | "homepage": "https://github.com/sebastianbergmann/code-unit",
838 | "support": {
839 | "issues": "https://github.com/sebastianbergmann/code-unit/issues",
840 | "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8"
841 | },
842 | "funding": [
843 | {
844 | "url": "https://github.com/sebastianbergmann",
845 | "type": "github"
846 | }
847 | ],
848 | "time": "2020-10-26T13:08:54+00:00"
849 | },
850 | {
851 | "name": "sebastian/code-unit-reverse-lookup",
852 | "version": "2.0.3",
853 | "source": {
854 | "type": "git",
855 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
856 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5"
857 | },
858 | "dist": {
859 | "type": "zip",
860 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
861 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
862 | "shasum": ""
863 | },
864 | "require": {
865 | "php": ">=7.3"
866 | },
867 | "require-dev": {
868 | "phpunit/phpunit": "^9.3"
869 | },
870 | "type": "library",
871 | "extra": {
872 | "branch-alias": {
873 | "dev-master": "2.0-dev"
874 | }
875 | },
876 | "autoload": {
877 | "classmap": [
878 | "src/"
879 | ]
880 | },
881 | "notification-url": "https://packagist.org/downloads/",
882 | "license": [
883 | "BSD-3-Clause"
884 | ],
885 | "authors": [
886 | {
887 | "name": "Sebastian Bergmann",
888 | "email": "sebastian@phpunit.de"
889 | }
890 | ],
891 | "description": "Looks up which function or method a line of code belongs to",
892 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
893 | "support": {
894 | "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
895 | "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3"
896 | },
897 | "funding": [
898 | {
899 | "url": "https://github.com/sebastianbergmann",
900 | "type": "github"
901 | }
902 | ],
903 | "time": "2020-09-28T05:30:19+00:00"
904 | },
905 | {
906 | "name": "sebastian/comparator",
907 | "version": "4.0.8",
908 | "source": {
909 | "type": "git",
910 | "url": "https://github.com/sebastianbergmann/comparator.git",
911 | "reference": "fa0f136dd2334583309d32b62544682ee972b51a"
912 | },
913 | "dist": {
914 | "type": "zip",
915 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a",
916 | "reference": "fa0f136dd2334583309d32b62544682ee972b51a",
917 | "shasum": ""
918 | },
919 | "require": {
920 | "php": ">=7.3",
921 | "sebastian/diff": "^4.0",
922 | "sebastian/exporter": "^4.0"
923 | },
924 | "require-dev": {
925 | "phpunit/phpunit": "^9.3"
926 | },
927 | "type": "library",
928 | "extra": {
929 | "branch-alias": {
930 | "dev-master": "4.0-dev"
931 | }
932 | },
933 | "autoload": {
934 | "classmap": [
935 | "src/"
936 | ]
937 | },
938 | "notification-url": "https://packagist.org/downloads/",
939 | "license": [
940 | "BSD-3-Clause"
941 | ],
942 | "authors": [
943 | {
944 | "name": "Sebastian Bergmann",
945 | "email": "sebastian@phpunit.de"
946 | },
947 | {
948 | "name": "Jeff Welch",
949 | "email": "whatthejeff@gmail.com"
950 | },
951 | {
952 | "name": "Volker Dusch",
953 | "email": "github@wallbash.com"
954 | },
955 | {
956 | "name": "Bernhard Schussek",
957 | "email": "bschussek@2bepublished.at"
958 | }
959 | ],
960 | "description": "Provides the functionality to compare PHP values for equality",
961 | "homepage": "https://github.com/sebastianbergmann/comparator",
962 | "keywords": [
963 | "comparator",
964 | "compare",
965 | "equality"
966 | ],
967 | "support": {
968 | "issues": "https://github.com/sebastianbergmann/comparator/issues",
969 | "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
970 | },
971 | "funding": [
972 | {
973 | "url": "https://github.com/sebastianbergmann",
974 | "type": "github"
975 | }
976 | ],
977 | "time": "2022-09-14T12:41:17+00:00"
978 | },
979 | {
980 | "name": "sebastian/complexity",
981 | "version": "2.0.3",
982 | "source": {
983 | "type": "git",
984 | "url": "https://github.com/sebastianbergmann/complexity.git",
985 | "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a"
986 | },
987 | "dist": {
988 | "type": "zip",
989 | "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a",
990 | "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a",
991 | "shasum": ""
992 | },
993 | "require": {
994 | "nikic/php-parser": "^4.18 || ^5.0",
995 | "php": ">=7.3"
996 | },
997 | "require-dev": {
998 | "phpunit/phpunit": "^9.3"
999 | },
1000 | "type": "library",
1001 | "extra": {
1002 | "branch-alias": {
1003 | "dev-master": "2.0-dev"
1004 | }
1005 | },
1006 | "autoload": {
1007 | "classmap": [
1008 | "src/"
1009 | ]
1010 | },
1011 | "notification-url": "https://packagist.org/downloads/",
1012 | "license": [
1013 | "BSD-3-Clause"
1014 | ],
1015 | "authors": [
1016 | {
1017 | "name": "Sebastian Bergmann",
1018 | "email": "sebastian@phpunit.de",
1019 | "role": "lead"
1020 | }
1021 | ],
1022 | "description": "Library for calculating the complexity of PHP code units",
1023 | "homepage": "https://github.com/sebastianbergmann/complexity",
1024 | "support": {
1025 | "issues": "https://github.com/sebastianbergmann/complexity/issues",
1026 | "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3"
1027 | },
1028 | "funding": [
1029 | {
1030 | "url": "https://github.com/sebastianbergmann",
1031 | "type": "github"
1032 | }
1033 | ],
1034 | "time": "2023-12-22T06:19:30+00:00"
1035 | },
1036 | {
1037 | "name": "sebastian/diff",
1038 | "version": "4.0.6",
1039 | "source": {
1040 | "type": "git",
1041 | "url": "https://github.com/sebastianbergmann/diff.git",
1042 | "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc"
1043 | },
1044 | "dist": {
1045 | "type": "zip",
1046 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc",
1047 | "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc",
1048 | "shasum": ""
1049 | },
1050 | "require": {
1051 | "php": ">=7.3"
1052 | },
1053 | "require-dev": {
1054 | "phpunit/phpunit": "^9.3",
1055 | "symfony/process": "^4.2 || ^5"
1056 | },
1057 | "type": "library",
1058 | "extra": {
1059 | "branch-alias": {
1060 | "dev-master": "4.0-dev"
1061 | }
1062 | },
1063 | "autoload": {
1064 | "classmap": [
1065 | "src/"
1066 | ]
1067 | },
1068 | "notification-url": "https://packagist.org/downloads/",
1069 | "license": [
1070 | "BSD-3-Clause"
1071 | ],
1072 | "authors": [
1073 | {
1074 | "name": "Sebastian Bergmann",
1075 | "email": "sebastian@phpunit.de"
1076 | },
1077 | {
1078 | "name": "Kore Nordmann",
1079 | "email": "mail@kore-nordmann.de"
1080 | }
1081 | ],
1082 | "description": "Diff implementation",
1083 | "homepage": "https://github.com/sebastianbergmann/diff",
1084 | "keywords": [
1085 | "diff",
1086 | "udiff",
1087 | "unidiff",
1088 | "unified diff"
1089 | ],
1090 | "support": {
1091 | "issues": "https://github.com/sebastianbergmann/diff/issues",
1092 | "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6"
1093 | },
1094 | "funding": [
1095 | {
1096 | "url": "https://github.com/sebastianbergmann",
1097 | "type": "github"
1098 | }
1099 | ],
1100 | "time": "2024-03-02T06:30:58+00:00"
1101 | },
1102 | {
1103 | "name": "sebastian/environment",
1104 | "version": "5.1.5",
1105 | "source": {
1106 | "type": "git",
1107 | "url": "https://github.com/sebastianbergmann/environment.git",
1108 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed"
1109 | },
1110 | "dist": {
1111 | "type": "zip",
1112 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
1113 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
1114 | "shasum": ""
1115 | },
1116 | "require": {
1117 | "php": ">=7.3"
1118 | },
1119 | "require-dev": {
1120 | "phpunit/phpunit": "^9.3"
1121 | },
1122 | "suggest": {
1123 | "ext-posix": "*"
1124 | },
1125 | "type": "library",
1126 | "extra": {
1127 | "branch-alias": {
1128 | "dev-master": "5.1-dev"
1129 | }
1130 | },
1131 | "autoload": {
1132 | "classmap": [
1133 | "src/"
1134 | ]
1135 | },
1136 | "notification-url": "https://packagist.org/downloads/",
1137 | "license": [
1138 | "BSD-3-Clause"
1139 | ],
1140 | "authors": [
1141 | {
1142 | "name": "Sebastian Bergmann",
1143 | "email": "sebastian@phpunit.de"
1144 | }
1145 | ],
1146 | "description": "Provides functionality to handle HHVM/PHP environments",
1147 | "homepage": "http://www.github.com/sebastianbergmann/environment",
1148 | "keywords": [
1149 | "Xdebug",
1150 | "environment",
1151 | "hhvm"
1152 | ],
1153 | "support": {
1154 | "issues": "https://github.com/sebastianbergmann/environment/issues",
1155 | "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5"
1156 | },
1157 | "funding": [
1158 | {
1159 | "url": "https://github.com/sebastianbergmann",
1160 | "type": "github"
1161 | }
1162 | ],
1163 | "time": "2023-02-03T06:03:51+00:00"
1164 | },
1165 | {
1166 | "name": "sebastian/exporter",
1167 | "version": "4.0.6",
1168 | "source": {
1169 | "type": "git",
1170 | "url": "https://github.com/sebastianbergmann/exporter.git",
1171 | "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72"
1172 | },
1173 | "dist": {
1174 | "type": "zip",
1175 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72",
1176 | "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72",
1177 | "shasum": ""
1178 | },
1179 | "require": {
1180 | "php": ">=7.3",
1181 | "sebastian/recursion-context": "^4.0"
1182 | },
1183 | "require-dev": {
1184 | "ext-mbstring": "*",
1185 | "phpunit/phpunit": "^9.3"
1186 | },
1187 | "type": "library",
1188 | "extra": {
1189 | "branch-alias": {
1190 | "dev-master": "4.0-dev"
1191 | }
1192 | },
1193 | "autoload": {
1194 | "classmap": [
1195 | "src/"
1196 | ]
1197 | },
1198 | "notification-url": "https://packagist.org/downloads/",
1199 | "license": [
1200 | "BSD-3-Clause"
1201 | ],
1202 | "authors": [
1203 | {
1204 | "name": "Sebastian Bergmann",
1205 | "email": "sebastian@phpunit.de"
1206 | },
1207 | {
1208 | "name": "Jeff Welch",
1209 | "email": "whatthejeff@gmail.com"
1210 | },
1211 | {
1212 | "name": "Volker Dusch",
1213 | "email": "github@wallbash.com"
1214 | },
1215 | {
1216 | "name": "Adam Harvey",
1217 | "email": "aharvey@php.net"
1218 | },
1219 | {
1220 | "name": "Bernhard Schussek",
1221 | "email": "bschussek@gmail.com"
1222 | }
1223 | ],
1224 | "description": "Provides the functionality to export PHP variables for visualization",
1225 | "homepage": "https://www.github.com/sebastianbergmann/exporter",
1226 | "keywords": [
1227 | "export",
1228 | "exporter"
1229 | ],
1230 | "support": {
1231 | "issues": "https://github.com/sebastianbergmann/exporter/issues",
1232 | "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
1233 | },
1234 | "funding": [
1235 | {
1236 | "url": "https://github.com/sebastianbergmann",
1237 | "type": "github"
1238 | }
1239 | ],
1240 | "time": "2024-03-02T06:33:00+00:00"
1241 | },
1242 | {
1243 | "name": "sebastian/global-state",
1244 | "version": "5.0.7",
1245 | "source": {
1246 | "type": "git",
1247 | "url": "https://github.com/sebastianbergmann/global-state.git",
1248 | "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9"
1249 | },
1250 | "dist": {
1251 | "type": "zip",
1252 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
1253 | "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
1254 | "shasum": ""
1255 | },
1256 | "require": {
1257 | "php": ">=7.3",
1258 | "sebastian/object-reflector": "^2.0",
1259 | "sebastian/recursion-context": "^4.0"
1260 | },
1261 | "require-dev": {
1262 | "ext-dom": "*",
1263 | "phpunit/phpunit": "^9.3"
1264 | },
1265 | "suggest": {
1266 | "ext-uopz": "*"
1267 | },
1268 | "type": "library",
1269 | "extra": {
1270 | "branch-alias": {
1271 | "dev-master": "5.0-dev"
1272 | }
1273 | },
1274 | "autoload": {
1275 | "classmap": [
1276 | "src/"
1277 | ]
1278 | },
1279 | "notification-url": "https://packagist.org/downloads/",
1280 | "license": [
1281 | "BSD-3-Clause"
1282 | ],
1283 | "authors": [
1284 | {
1285 | "name": "Sebastian Bergmann",
1286 | "email": "sebastian@phpunit.de"
1287 | }
1288 | ],
1289 | "description": "Snapshotting of global state",
1290 | "homepage": "http://www.github.com/sebastianbergmann/global-state",
1291 | "keywords": [
1292 | "global state"
1293 | ],
1294 | "support": {
1295 | "issues": "https://github.com/sebastianbergmann/global-state/issues",
1296 | "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
1297 | },
1298 | "funding": [
1299 | {
1300 | "url": "https://github.com/sebastianbergmann",
1301 | "type": "github"
1302 | }
1303 | ],
1304 | "time": "2024-03-02T06:35:11+00:00"
1305 | },
1306 | {
1307 | "name": "sebastian/lines-of-code",
1308 | "version": "1.0.4",
1309 | "source": {
1310 | "type": "git",
1311 | "url": "https://github.com/sebastianbergmann/lines-of-code.git",
1312 | "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5"
1313 | },
1314 | "dist": {
1315 | "type": "zip",
1316 | "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5",
1317 | "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5",
1318 | "shasum": ""
1319 | },
1320 | "require": {
1321 | "nikic/php-parser": "^4.18 || ^5.0",
1322 | "php": ">=7.3"
1323 | },
1324 | "require-dev": {
1325 | "phpunit/phpunit": "^9.3"
1326 | },
1327 | "type": "library",
1328 | "extra": {
1329 | "branch-alias": {
1330 | "dev-master": "1.0-dev"
1331 | }
1332 | },
1333 | "autoload": {
1334 | "classmap": [
1335 | "src/"
1336 | ]
1337 | },
1338 | "notification-url": "https://packagist.org/downloads/",
1339 | "license": [
1340 | "BSD-3-Clause"
1341 | ],
1342 | "authors": [
1343 | {
1344 | "name": "Sebastian Bergmann",
1345 | "email": "sebastian@phpunit.de",
1346 | "role": "lead"
1347 | }
1348 | ],
1349 | "description": "Library for counting the lines of code in PHP source code",
1350 | "homepage": "https://github.com/sebastianbergmann/lines-of-code",
1351 | "support": {
1352 | "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
1353 | "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4"
1354 | },
1355 | "funding": [
1356 | {
1357 | "url": "https://github.com/sebastianbergmann",
1358 | "type": "github"
1359 | }
1360 | ],
1361 | "time": "2023-12-22T06:20:34+00:00"
1362 | },
1363 | {
1364 | "name": "sebastian/object-enumerator",
1365 | "version": "4.0.4",
1366 | "source": {
1367 | "type": "git",
1368 | "url": "https://github.com/sebastianbergmann/object-enumerator.git",
1369 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71"
1370 | },
1371 | "dist": {
1372 | "type": "zip",
1373 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71",
1374 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71",
1375 | "shasum": ""
1376 | },
1377 | "require": {
1378 | "php": ">=7.3",
1379 | "sebastian/object-reflector": "^2.0",
1380 | "sebastian/recursion-context": "^4.0"
1381 | },
1382 | "require-dev": {
1383 | "phpunit/phpunit": "^9.3"
1384 | },
1385 | "type": "library",
1386 | "extra": {
1387 | "branch-alias": {
1388 | "dev-master": "4.0-dev"
1389 | }
1390 | },
1391 | "autoload": {
1392 | "classmap": [
1393 | "src/"
1394 | ]
1395 | },
1396 | "notification-url": "https://packagist.org/downloads/",
1397 | "license": [
1398 | "BSD-3-Clause"
1399 | ],
1400 | "authors": [
1401 | {
1402 | "name": "Sebastian Bergmann",
1403 | "email": "sebastian@phpunit.de"
1404 | }
1405 | ],
1406 | "description": "Traverses array structures and object graphs to enumerate all referenced objects",
1407 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
1408 | "support": {
1409 | "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
1410 | "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4"
1411 | },
1412 | "funding": [
1413 | {
1414 | "url": "https://github.com/sebastianbergmann",
1415 | "type": "github"
1416 | }
1417 | ],
1418 | "time": "2020-10-26T13:12:34+00:00"
1419 | },
1420 | {
1421 | "name": "sebastian/object-reflector",
1422 | "version": "2.0.4",
1423 | "source": {
1424 | "type": "git",
1425 | "url": "https://github.com/sebastianbergmann/object-reflector.git",
1426 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7"
1427 | },
1428 | "dist": {
1429 | "type": "zip",
1430 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
1431 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
1432 | "shasum": ""
1433 | },
1434 | "require": {
1435 | "php": ">=7.3"
1436 | },
1437 | "require-dev": {
1438 | "phpunit/phpunit": "^9.3"
1439 | },
1440 | "type": "library",
1441 | "extra": {
1442 | "branch-alias": {
1443 | "dev-master": "2.0-dev"
1444 | }
1445 | },
1446 | "autoload": {
1447 | "classmap": [
1448 | "src/"
1449 | ]
1450 | },
1451 | "notification-url": "https://packagist.org/downloads/",
1452 | "license": [
1453 | "BSD-3-Clause"
1454 | ],
1455 | "authors": [
1456 | {
1457 | "name": "Sebastian Bergmann",
1458 | "email": "sebastian@phpunit.de"
1459 | }
1460 | ],
1461 | "description": "Allows reflection of object attributes, including inherited and non-public ones",
1462 | "homepage": "https://github.com/sebastianbergmann/object-reflector/",
1463 | "support": {
1464 | "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
1465 | "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4"
1466 | },
1467 | "funding": [
1468 | {
1469 | "url": "https://github.com/sebastianbergmann",
1470 | "type": "github"
1471 | }
1472 | ],
1473 | "time": "2020-10-26T13:14:26+00:00"
1474 | },
1475 | {
1476 | "name": "sebastian/recursion-context",
1477 | "version": "4.0.5",
1478 | "source": {
1479 | "type": "git",
1480 | "url": "https://github.com/sebastianbergmann/recursion-context.git",
1481 | "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1"
1482 | },
1483 | "dist": {
1484 | "type": "zip",
1485 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
1486 | "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
1487 | "shasum": ""
1488 | },
1489 | "require": {
1490 | "php": ">=7.3"
1491 | },
1492 | "require-dev": {
1493 | "phpunit/phpunit": "^9.3"
1494 | },
1495 | "type": "library",
1496 | "extra": {
1497 | "branch-alias": {
1498 | "dev-master": "4.0-dev"
1499 | }
1500 | },
1501 | "autoload": {
1502 | "classmap": [
1503 | "src/"
1504 | ]
1505 | },
1506 | "notification-url": "https://packagist.org/downloads/",
1507 | "license": [
1508 | "BSD-3-Clause"
1509 | ],
1510 | "authors": [
1511 | {
1512 | "name": "Sebastian Bergmann",
1513 | "email": "sebastian@phpunit.de"
1514 | },
1515 | {
1516 | "name": "Jeff Welch",
1517 | "email": "whatthejeff@gmail.com"
1518 | },
1519 | {
1520 | "name": "Adam Harvey",
1521 | "email": "aharvey@php.net"
1522 | }
1523 | ],
1524 | "description": "Provides functionality to recursively process PHP variables",
1525 | "homepage": "https://github.com/sebastianbergmann/recursion-context",
1526 | "support": {
1527 | "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
1528 | "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5"
1529 | },
1530 | "funding": [
1531 | {
1532 | "url": "https://github.com/sebastianbergmann",
1533 | "type": "github"
1534 | }
1535 | ],
1536 | "time": "2023-02-03T06:07:39+00:00"
1537 | },
1538 | {
1539 | "name": "sebastian/resource-operations",
1540 | "version": "3.0.4",
1541 | "source": {
1542 | "type": "git",
1543 | "url": "https://github.com/sebastianbergmann/resource-operations.git",
1544 | "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e"
1545 | },
1546 | "dist": {
1547 | "type": "zip",
1548 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
1549 | "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
1550 | "shasum": ""
1551 | },
1552 | "require": {
1553 | "php": ">=7.3"
1554 | },
1555 | "require-dev": {
1556 | "phpunit/phpunit": "^9.0"
1557 | },
1558 | "type": "library",
1559 | "extra": {
1560 | "branch-alias": {
1561 | "dev-main": "3.0-dev"
1562 | }
1563 | },
1564 | "autoload": {
1565 | "classmap": [
1566 | "src/"
1567 | ]
1568 | },
1569 | "notification-url": "https://packagist.org/downloads/",
1570 | "license": [
1571 | "BSD-3-Clause"
1572 | ],
1573 | "authors": [
1574 | {
1575 | "name": "Sebastian Bergmann",
1576 | "email": "sebastian@phpunit.de"
1577 | }
1578 | ],
1579 | "description": "Provides a list of PHP built-in functions that operate on resources",
1580 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
1581 | "support": {
1582 | "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4"
1583 | },
1584 | "funding": [
1585 | {
1586 | "url": "https://github.com/sebastianbergmann",
1587 | "type": "github"
1588 | }
1589 | ],
1590 | "time": "2024-03-14T16:00:52+00:00"
1591 | },
1592 | {
1593 | "name": "sebastian/type",
1594 | "version": "3.2.1",
1595 | "source": {
1596 | "type": "git",
1597 | "url": "https://github.com/sebastianbergmann/type.git",
1598 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7"
1599 | },
1600 | "dist": {
1601 | "type": "zip",
1602 | "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
1603 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
1604 | "shasum": ""
1605 | },
1606 | "require": {
1607 | "php": ">=7.3"
1608 | },
1609 | "require-dev": {
1610 | "phpunit/phpunit": "^9.5"
1611 | },
1612 | "type": "library",
1613 | "extra": {
1614 | "branch-alias": {
1615 | "dev-master": "3.2-dev"
1616 | }
1617 | },
1618 | "autoload": {
1619 | "classmap": [
1620 | "src/"
1621 | ]
1622 | },
1623 | "notification-url": "https://packagist.org/downloads/",
1624 | "license": [
1625 | "BSD-3-Clause"
1626 | ],
1627 | "authors": [
1628 | {
1629 | "name": "Sebastian Bergmann",
1630 | "email": "sebastian@phpunit.de",
1631 | "role": "lead"
1632 | }
1633 | ],
1634 | "description": "Collection of value objects that represent the types of the PHP type system",
1635 | "homepage": "https://github.com/sebastianbergmann/type",
1636 | "support": {
1637 | "issues": "https://github.com/sebastianbergmann/type/issues",
1638 | "source": "https://github.com/sebastianbergmann/type/tree/3.2.1"
1639 | },
1640 | "funding": [
1641 | {
1642 | "url": "https://github.com/sebastianbergmann",
1643 | "type": "github"
1644 | }
1645 | ],
1646 | "time": "2023-02-03T06:13:03+00:00"
1647 | },
1648 | {
1649 | "name": "sebastian/version",
1650 | "version": "3.0.2",
1651 | "source": {
1652 | "type": "git",
1653 | "url": "https://github.com/sebastianbergmann/version.git",
1654 | "reference": "c6c1022351a901512170118436c764e473f6de8c"
1655 | },
1656 | "dist": {
1657 | "type": "zip",
1658 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c",
1659 | "reference": "c6c1022351a901512170118436c764e473f6de8c",
1660 | "shasum": ""
1661 | },
1662 | "require": {
1663 | "php": ">=7.3"
1664 | },
1665 | "type": "library",
1666 | "extra": {
1667 | "branch-alias": {
1668 | "dev-master": "3.0-dev"
1669 | }
1670 | },
1671 | "autoload": {
1672 | "classmap": [
1673 | "src/"
1674 | ]
1675 | },
1676 | "notification-url": "https://packagist.org/downloads/",
1677 | "license": [
1678 | "BSD-3-Clause"
1679 | ],
1680 | "authors": [
1681 | {
1682 | "name": "Sebastian Bergmann",
1683 | "email": "sebastian@phpunit.de",
1684 | "role": "lead"
1685 | }
1686 | ],
1687 | "description": "Library that helps with managing the version number of Git-hosted PHP projects",
1688 | "homepage": "https://github.com/sebastianbergmann/version",
1689 | "support": {
1690 | "issues": "https://github.com/sebastianbergmann/version/issues",
1691 | "source": "https://github.com/sebastianbergmann/version/tree/3.0.2"
1692 | },
1693 | "funding": [
1694 | {
1695 | "url": "https://github.com/sebastianbergmann",
1696 | "type": "github"
1697 | }
1698 | ],
1699 | "time": "2020-09-28T06:39:44+00:00"
1700 | },
1701 | {
1702 | "name": "theseer/tokenizer",
1703 | "version": "1.2.3",
1704 | "source": {
1705 | "type": "git",
1706 | "url": "https://github.com/theseer/tokenizer.git",
1707 | "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
1708 | },
1709 | "dist": {
1710 | "type": "zip",
1711 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
1712 | "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
1713 | "shasum": ""
1714 | },
1715 | "require": {
1716 | "ext-dom": "*",
1717 | "ext-tokenizer": "*",
1718 | "ext-xmlwriter": "*",
1719 | "php": "^7.2 || ^8.0"
1720 | },
1721 | "type": "library",
1722 | "autoload": {
1723 | "classmap": [
1724 | "src/"
1725 | ]
1726 | },
1727 | "notification-url": "https://packagist.org/downloads/",
1728 | "license": [
1729 | "BSD-3-Clause"
1730 | ],
1731 | "authors": [
1732 | {
1733 | "name": "Arne Blankerts",
1734 | "email": "arne@blankerts.de",
1735 | "role": "Developer"
1736 | }
1737 | ],
1738 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
1739 | "support": {
1740 | "issues": "https://github.com/theseer/tokenizer/issues",
1741 | "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
1742 | },
1743 | "funding": [
1744 | {
1745 | "url": "https://github.com/theseer",
1746 | "type": "github"
1747 | }
1748 | ],
1749 | "time": "2024-03-03T12:36:25+00:00"
1750 | }
1751 | ],
1752 | "aliases": [],
1753 | "minimum-stability": "stable",
1754 | "stability-flags": {},
1755 | "prefer-stable": false,
1756 | "prefer-lowest": false,
1757 | "platform": {},
1758 | "platform-dev": {},
1759 | "platform-overrides": {
1760 | "php": "8.1"
1761 | },
1762 | "plugin-api-version": "2.6.0"
1763 | }
1764 |
--------------------------------------------------------------------------------
/vendor-bin/psalm/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "require-dev": {
3 | "vimeo/psalm": "^6"
4 | },
5 | "config": {
6 | "platform": {
7 | "php": "8.1.17"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------