Skip to content

Commit

Permalink
Create move to docker script with a proper CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
rick-nu committed Jan 26, 2024
1 parent bbbf394 commit b28c9a9
Show file tree
Hide file tree
Showing 15 changed files with 2,210 additions and 653 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@
# Generated files

node_modules/
src/vendor/
src/.env
28 changes: 27 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1 +1,27 @@
FROM node:20-alpine
FROM php:8.3-cli AS base

COPY ./src /opt/dropbox-uploader

WORKDIR /opt/dropbox-uploader

FROM base AS local

RUN apt update && apt install zip unzip

COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer

FROM local as dependencies

COPY ./src /opt/dropbox-uploader

RUN composer install --no-scripts --ignore-platform-reqs --no-ansi --no-interaction --optimize-autoloader

FROM base AS production

COPY ./src /opt/dropbox-uploader

COPY --from=dependencies /opt/dropbox-uploader/vendor /opt/dropbox-uploader/vendor

ENTRYPOINT ["php", "/opt/dropbox-uploader/cli.php"]

CMD ["upload"]
57 changes: 56 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,58 @@
# Upload To Dropbox

Single run to upload all files to dropbox in the mounted folder. Ideal for back-up scripts.
1) Uploads all files from the mounted folder to dropbox
2) Removes the files after a successful upload

Ideal for back-ups.

Known limitations:

- Breaks when there are folders in your locally mounted folder (this is not supported)

## Environment variables

- `DROPBOX_APP_KEY`: create your own dropbox app to get this
- `DROPBOX_APP_SECRET`: create your own dropbox app to get this
- `DROPBOX_REFRESH_TOKEN`: generate using `<this container> authorize`
- Mount the folder (of which you want to move its files to dropbox) to `/opt/dropbox-uploader/uploads/`

## Running locally

- `./Taskfile`

Create file `./src/.env` with the environment variables above.

## Running with docker

Run the following docker command. In this example we mounted to `./backups` folder.

```bash
docker run \
--rm \
--tty \
--interactive \
--volume ./backups:/opt/dropbox-uploader/uploads \
--env DROPBOX_APP_KEY=redacted \
--env DROPBOX_APP_SECRET=redacted \
--env DROPBOX_REFRESH_TOKEN=redacted \
registry.gitlab.com/futureportal/uploadtodropbox:latest
```

## Running with docker compose

Add this to `docker-compose.yml`, and run `docker compose up`. In this example we mounted to `./backups` folder.

```yml
version: '3'

services:
dropbox:
image: registry.gitlab.com/futureportal/uploadtodropbox:latest
container_name: dropbox-backup-upload
environment:
- DROPBOX_APP_KEY=redacted
- DROPBOX_APP_SECRET=redacted
- DROPBOX_REFRESH_TOKEN=redacted
volumes:
- ./backups:/opt/dropbox-uploader/uploads
```
67 changes: 20 additions & 47 deletions Taskfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/bin/bash
set -eo pipefail

# =========================================================
# Taskfile gives you a set of quick tasks for your project
Expand All @@ -11,74 +10,47 @@ set -eo pipefail
# =========================================================

function task:init { ## Initialise the project for local development
docker:down
docker:build
docker:start
task:build
project:update
task:help
}

function task:update { ## Update all dependencies and files
project:update
}

function project:update {
title "Installing dependencies"
yarn install
docker:run composer install
}

# =========================================================
## Local development
# =========================================================

function task:start { ## Start the project containers via docker compose
docker:start
}

function task:stop { ## Stop the project containers
docker:stop
}

function task:build { ## (re)build the project containers
docker:build
function task:build { ## (re)build the project container
title "Building local container"
docker build --target local --tag upload-to-dropbox:local .
title "Building production container"
docker build --target production --tag upload-to-dropbox:production .
}

function task:restart { ## Restart the project containers
docker:stop
docker:start
function task:run { ## Run the CLI
title "Running the production container"
docker run -ti --rm --volume $PWD/src:/opt/dropbox-uploader --user `id -u`:`id -g` --name upload-to-dropbox upload-to-dropbox:production "$@"
}

function task:logs { ## Show container logs
docker:logs
function task:shell { ## Open the local development shell
title "Running the development shell"
docker:run /bin/sh
}

# =========================================================
# Docker
# =========================================================

function docker:compose {
USERID=$(id -u) GROUPID=$(id -g) docker compose "$@"
}

function docker:start {
docker:compose up --detach
}

function docker:stop {
title "Stopping project containers"
docker network disconnect nawcast development-proxy || true
docker:compose stop
}

function docker:build {
title "Building project containers"
docker:compose build --no-cache
}

function docker:down {
title "Destroying project containers"
docker:compose down --volumes
}

function docker:logs {
title "Showing container logs"
docker:compose logs --tail="10" --follow
function docker:run {
docker run -ti --rm --volume $PWD/src:/opt/dropbox-uploader --user `id -u`:`id -g` upload-to-dropbox:local "$@"
}

# =========================================================
Expand Down Expand Up @@ -133,5 +105,6 @@ function task:shorthand { ## Create CLI shorthand task instead of ./Taskfile
}

# Execute tasks (defaults to help)
set -eo pipefail
banner
"task:${@:-help}"
5 changes: 1 addition & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@
},
"license": "MIT",
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@prettier/plugin-php": "^0.22.1",
"prettier": "^3.2.4"
},
"dependencies": {
"dropbox-v2-api": "^2.5.10"
}
}
14 changes: 1 addition & 13 deletions prettier.config.mjs
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@
export default {
plugins: ['@trivago/prettier-plugin-sort-imports'],
plugins: ["@prettier/plugin-php"],
printWidth: 120,
semi: true,
useTabs: true,
singleQuote: true,
bracketSpacing: true,
trailingComma: 'es5',
importOrder: [
'^react$',
'<THIRD_PARTY_MODULES>',
'^main/(.*)$',
'^dashboard/(.*)$',
'^runner/(.*)$',
'^shared/(.*)$',
'^[../]',
'^[./]',
],
importOrderSeparation: true,
importOrderSortSpecifiers: true,
};
25 changes: 25 additions & 0 deletions src/Auth/DropboxTokenProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace FuturePortal\DropboxUploader\Auth;

use Spatie\Dropbox\TokenProvider;
use Stevenmaguire\OAuth2\Client\Provider\Dropbox;

class DropboxTokenProvider implements TokenProvider
{
public function getToken(): string
{
$authClient = new Dropbox([
'clientId' => $_ENV['DROPBOX_APP_KEY'],
'clientSecret' => $_ENV['DROPBOX_APP_SECRET'],
// 'redirectUri' => '' // no redirect, we want a long-lasting offline token
]);

// Try to get an access token (using the authorization code grant)
$token = $authClient->getAccessToken('refresh_token', [
'refresh_token' => $_ENV['DROPBOX_REFRESH_TOKEN']
]);

return $token->getToken();
}
}
122 changes: 122 additions & 0 deletions src/Command/UploadCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?php

namespace FuturePortal\DropboxUploader\Command;

use Dotenv\Dotenv;
use FuturePortal\DropboxUploader\Auth\DropboxTokenProvider;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Spatie\Dropbox\Client;

#[AsCommand(
name: 'upload',
description: 'Uploads all files to the cloud.',
)]
class UploadCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output): int
{
$dotenv = Dotenv::createImmutable(__DIR__ . '/../');
if (file_exists(__DIR__ . '/../.env')) {
$dotenv->load();
}

$dotenv->required('DROPBOX_APP_KEY');
$dotenv->required('DROPBOX_APP_SECRET');
$dotenv->required('DROPBOX_REFRESH_TOKEN');

$files = $this->getLocalFiles($output);

if (count($files) === 0) {
$output->writeln('No files to upload.');
return Command::SUCCESS;
}

try {
$this->uploadFiles($files, $output);
} catch (\Exception $exception) {
return Command::FAILURE;
}

return Command::SUCCESS;
}

private function getLocalFiles(OutputInterface $output): array
{
$output->writeln('Checking files to upload...');

$files = scandir(__DIR__ . '/../uploads');

$files = array_filter($files, function($file) {
return $file !== '.' && $file !== '..';
});

$count = count($files);
$output->writeln('Found ' . $count . ' file' . ($count === 1 ? '' : 's') . '.');

return $files;
}

private function uploadFiles(array $files, OutputInterface $output): void
{
try {
$tokenProvider = new DropboxTokenProvider();
$client = new Client($tokenProvider);
} catch (\Exception $exception) {
$output->writeln("Error setting up dropbox client.");
$output->writeln($exception->getMessage());
throw $exception;
}

$output->writeln('Uploading files to the cloud...');

foreach ($files as $file) {
$output->write("Uploading $file... ");
try {
$localFile = __DIR__ . '/../uploads/' . $file;

$client->upload($file, file_get_contents($localFile));

$output->write("OK");
unlink($localFile);
$output->writeln(".");
}
catch (\Exception $exception) {
$output->writeln("ERROR");
$output->writeln($exception->getMessage());
}
}

$output->writeln('Done uploading!');
}

// private function getOnlineFiles(OutputInterface $output): array
// {
// $output->writeln('Checking files in the cloud...');
//
// $tokenProvider = new DropboxTokenProvider();
// $client = new Client($tokenProvider);
//
// $files = $client->listFolder()['entries'];
//
// foreach ($files as $file) {
// $output->writeln(' - ' . $file['name']);
// }
//
// // [.tag] => file
// // [name] => 2024-01-13-home-assistant.tar
// // [path_lower] => /2024-01-13-home-assistant.tar
// // [path_display] => /2024-01-13-home-assistant.tar
// // [id] => id:e7tN9Yj6WMIAAAAAAAAAGQ
// // [client_modified] => 2024-01-13T04:00:01Z
// // [server_modified] => 2024-01-13T04:00:04Z
// // [rev] => 60ecbd0c8efc0854ab923
// // [size] => 9881600
// // [is_downloadable] => 1
// // [content_hash] => 4fda9fbf698cd7e42d2f3e1dae29738fd63ae291a85b377c3880e27ca540036
//
// return [];
// }
}
Loading

0 comments on commit b28c9a9

Please sign in to comment.