Merge pull request #112898 from erictapen/feature/mastodon

mastodon,nixos/mastodon: init at 3.3.0
This commit is contained in:
adisbladis 2021-02-12 17:00:21 +01:00 committed by GitHub
commit 706c4d3fb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 16276 additions and 0 deletions

View File

@ -3615,6 +3615,12 @@
githubId = 5317234;
name = "Raphael Megzari";
};
happy-river = {
email = "happyriver93@runbox.com";
github = "happy-river";
githubId = 54728477;
name = "Happy River";
};
haslersn = {
email = "haslersn@fius.informatik.uni-stuttgart.de";
github = "haslersn";

View File

@ -891,6 +891,7 @@
./services/web-apps/jitsi-meet.nix
./services/web-apps/keycloak.nix
./services/web-apps/limesurvey.nix
./services/web-apps/mastodon.nix
./services/web-apps/mattermost.nix
./services/web-apps/mediawiki.nix
./services/web-apps/miniflux.nix

View File

@ -0,0 +1,541 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.mastodon;
# We only want to create a database if we're actually going to connect to it.
databaseActuallyCreateLocally = cfg.database.createLocally && cfg.database.host == "/run/postgresql";
env = {
RAILS_ENV = "production";
NODE_ENV = "production";
DB_USER = cfg.database.user;
REDIS_HOST = cfg.redis.host;
REDIS_PORT = toString(cfg.redis.port);
DB_HOST = cfg.database.host;
DB_PORT = toString(cfg.database.port);
DB_NAME = cfg.database.name;
LOCAL_DOMAIN = cfg.localDomain;
SMTP_SERVER = cfg.smtp.host;
SMTP_PORT = toString(cfg.smtp.port);
SMTP_FROM_ADDRESS = cfg.smtp.fromAddress;
PAPERCLIP_ROOT_PATH = "/var/lib/mastodon/public-system";
PAPERCLIP_ROOT_URL = "/system";
ES_ENABLED = if (cfg.elasticsearch.host != null) then "true" else "false";
ES_HOST = cfg.elasticsearch.host;
ES_PORT = toString(cfg.elasticsearch.port);
}
// (if cfg.smtp.authenticate then { SMTP_LOGIN = cfg.smtp.user; } else {})
// cfg.extraConfig;
envFile = pkgs.writeText "mastodon.env" (lib.concatMapStrings (s: s + "\n") (
(lib.concatLists (lib.mapAttrsToList (name: value:
if value != null then [
"${name}=\"${toString value}\""
] else []
) env))));
mastodonEnv = pkgs.writeShellScriptBin "mastodon-env" ''
set -a
source "${envFile}"
source /var/lib/mastodon/.secrets_env
eval -- "\$@"
'';
in {
options = {
services.mastodon = {
enable = lib.mkEnableOption "Mastodon, a federated social network server";
configureNginx = lib.mkOption {
description = ''
Configure nginx as a reverse proxy for mastodon.
Note that this makes some assumptions on your setup, and sets settings that will
affect other virtualHosts running on your nginx instance, if any.
Alternatively you can configure a reverse-proxy of your choice to serve these paths:
<code>/ -> $(nix-instantiate --eval '&lt;nixpkgs&gt;' -A mastodon.outPath)/public</code>
<code>/ -> 127.0.0.1:{{ webPort }} </code>(If there was no file in the directory above.)
<code>/system/ -> /var/lib/mastodon/public-system/</code>
<code>/api/v1/streaming/ -> 127.0.0.1:{{ streamingPort }}</code>
Make sure that websockets are forwarded properly. You might want to set up caching
of some requests. Take a look at mastodon's provided nginx configuration at
<code>https://github.com/tootsuite/mastodon/blob/master/dist/nginx.conf</code>.
'';
type = lib.types.bool;
default = false;
};
user = lib.mkOption {
description = ''
User under which mastodon runs. If it is set to "mastodon",
that user will be created, otherwise it should be set to the
name of a user created elsewhere. In both cases,
<package>mastodon</package> and a package containing only
the shell script <code>mastodon-env</code> will be added to
the user's package set. To run a command from
<package>mastodon</package> such as <code>tootctl</code>
with the environment configured by this module use
<code>mastodon-env</code>, as in:
<code>mastodon-env tootctl accounts create newuser --email newuser@example.com</code>
'';
type = lib.types.str;
default = "mastodon";
};
group = lib.mkOption {
description = ''
Group under which mastodon runs.
If it is set to "mastodon", a group will be created.
'';
type = lib.types.str;
default = "mastodon";
};
streamingPort = lib.mkOption {
description = "TCP port used by the mastodon-streaming service.";
type = lib.types.port;
default = 55000;
};
webPort = lib.mkOption {
description = "TCP port used by the mastodon-web service.";
type = lib.types.port;
default = 55001;
};
sidekiqPort = lib.mkOption {
description = "TCP port used by the mastodon-sidekiq service";
type = lib.types.port;
default = 55002;
};
vapidPublicKeyFile = lib.mkOption {
description = ''
Path to file containing the public key used for Web Push
Voluntary Application Server Identification. A new keypair can
be generated by running:
<code>nix build -f '&lt;nixpkgs&gt;' mastodon; cd result; bin/rake webpush:generate_keys</code>
If <option>mastodon.vapidPrivateKeyFile</option>does not
exist, it and this file will be created with a new keypair.
'';
default = "/var/lib/mastodon/secrets/vapid-public-key";
type = lib.types.str;
};
localDomain = lib.mkOption {
description = "The domain serving your Mastodon instance.";
example = "social.example.org";
type = lib.types.str;
};
secretKeyBaseFile = lib.mkOption {
description = ''
Path to file containing the secret key base.
A new secret key base can be generated by running:
<code>nix build -f '&lt;nixpkgs&gt;' mastodon; cd result; bin/rake secret</code>
If this file does not exist, it will be created with a new secret key base.
'';
default = "/var/lib/mastodon/secrets/secret-key-base";
type = lib.types.str;
};
otpSecretFile = lib.mkOption {
description = ''
Path to file containing the OTP secret.
A new OTP secret can be generated by running:
<code>nix build -f '&lt;nixpkgs&gt;' mastodon; cd result; bin/rake secret</code>
If this file does not exist, it will be created with a new OTP secret.
'';
default = "/var/lib/mastodon/secrets/otp-secret";
type = lib.types.str;
};
vapidPrivateKeyFile = lib.mkOption {
description = ''
Path to file containing the private key used for Web Push
Voluntary Application Server Identification. A new keypair can
be generated by running:
<code>nix build -f '&lt;nixpkgs&gt;' mastodon; cd result; bin/rake webpush:generate_keys</code>
If this file does not exist, it will be created with a new
private key.
'';
default = "/var/lib/mastodon/secrets/vapid-private-key";
type = lib.types.str;
};
redis = {
createLocally = lib.mkOption {
description = "Configure local Redis server for Mastodon.";
type = lib.types.bool;
default = true;
};
host = lib.mkOption {
description = "Redis host.";
type = lib.types.str;
default = "127.0.0.1";
};
port = lib.mkOption {
description = "Redis port.";
type = lib.types.port;
default = 6379;
};
};
database = {
createLocally = lib.mkOption {
description = "Configure local PostgreSQL database server for Mastodon.";
type = lib.types.bool;
default = true;
};
host = lib.mkOption {
type = lib.types.str;
default = "/run/postgresql";
example = "192.168.23.42";
description = "Database host address or unix socket.";
};
port = lib.mkOption {
type = lib.types.int;
default = 5432;
description = "Database host port.";
};
name = lib.mkOption {
type = lib.types.str;
default = "mastodon";
description = "Database name.";
};
user = lib.mkOption {
type = lib.types.str;
default = "mastodon";
description = "Database user.";
};
passwordFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = "/var/lib/mastodon/secrets/db-password";
example = "/run/keys/mastodon-db-password";
description = ''
A file containing the password corresponding to
<option>database.user</option>.
'';
};
};
smtp = {
createLocally = lib.mkOption {
description = "Configure local Postfix SMTP server for Mastodon.";
type = lib.types.bool;
default = true;
};
authenticate = lib.mkOption {
description = "Authenticate with the SMTP server using username and password.";
type = lib.types.bool;
default = true;
};
host = lib.mkOption {
description = "SMTP host used when sending emails to users.";
type = lib.types.str;
default = "127.0.0.1";
};
port = lib.mkOption {
description = "SMTP port used when sending emails to users.";
type = lib.types.port;
default = 25;
};
fromAddress = lib.mkOption {
description = ''"From" address used when sending Emails to users.'';
type = lib.types.str;
};
user = lib.mkOption {
description = "SMTP login name.";
type = lib.types.str;
};
passwordFile = lib.mkOption {
description = ''
Path to file containing the SMTP password.
'';
default = "/var/lib/mastodon/secrets/smtp-password";
example = "/run/keys/mastodon-smtp-password";
type = lib.types.str;
};
};
elasticsearch = {
host = lib.mkOption {
description = ''
Elasticsearch host.
If it is not null, Elasticsearch full text search will be enabled.
'';
type = lib.types.nullOr lib.types.str;
default = null;
};
port = lib.mkOption {
description = "Elasticsearch port.";
type = lib.types.port;
default = 9200;
};
};
package = lib.mkOption {
type = lib.types.package;
default = pkgs.mastodon;
defaultText = "pkgs.mastodon";
description = "Mastodon package to use.";
};
extraConfig = lib.mkOption {
type = lib.types.attrs;
default = {};
description = ''
Extra environment variables to pass to all mastodon services.
'';
};
automaticMigrations = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Do automatic database migrations.
'';
};
};
};
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = databaseActuallyCreateLocally -> (cfg.user == cfg.database.user);
message = ''For local automatic database provisioning (services.mastodon.database.createLocally == true) with peer authentication (services.mastodon.database.host == "/run/postgresql") to work services.mastodon.user and services.mastodon.database.user must be identical.'';
}
];
systemd.services.mastodon-init-dirs = {
script = ''
umask 077
if ! test -f ${cfg.secretKeyBaseFile}; then
mkdir -p $(dirname ${cfg.secretKeyBaseFile})
bin/rake secret > ${cfg.secretKeyBaseFile}
fi
if ! test -f ${cfg.otpSecretFile}; then
mkdir -p $(dirname ${cfg.otpSecretFile})
bin/rake secret > ${cfg.otpSecretFile}
fi
if ! test -f ${cfg.vapidPrivateKeyFile}; then
mkdir -p $(dirname ${cfg.vapidPrivateKeyFile}) $(dirname ${cfg.vapidPublicKeyFile})
keypair=$(bin/rake webpush:generate_keys)
echo $keypair | grep --only-matching "Private -> [^ ]\+" | sed 's/^Private -> //' > ${cfg.vapidPrivateKeyFile}
echo $keypair | grep --only-matching "Public -> [^ ]\+" | sed 's/^Public -> //' > ${cfg.vapidPublicKeyFile}
fi
cat > /var/lib/mastodon/.secrets_env <<EOF
SECRET_KEY_BASE="$(cat ${cfg.secretKeyBaseFile})"
OTP_SECRET="$(cat ${cfg.otpSecretFile})"
VAPID_PRIVATE_KEY="$(cat ${cfg.vapidPrivateKeyFile})"
VAPID_PUBLIC_KEY="$(cat ${cfg.vapidPublicKeyFile})"
DB_PASS="$(cat ${cfg.database.passwordFile})"
'' + (if cfg.smtp.authenticate then ''
SMTP_PASSWORD="$(cat ${cfg.smtp.passwordFile})"
'' else "") + ''
EOF
'';
serviceConfig = {
Type = "oneshot";
User = cfg.user;
Group = cfg.group;
WorkingDirectory = cfg.package;
LogsDirectory = "mastodon";
StateDirectory = "mastodon";
};
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
};
systemd.services.mastodon-init-db = lib.mkIf cfg.automaticMigrations {
script = ''
if [ `psql mastodon -c \
"select count(*) from pg_class c \
join pg_namespace s on s.oid = c.relnamespace \
where s.nspname not in ('pg_catalog', 'pg_toast', 'information_schema') \
and s.nspname not like 'pg_temp%';" | sed -n 3p` -eq 0 ]; then
SAFETY_ASSURED=1 rake db:schema:load
rake db:seed
else
rake db:migrate
fi
'';
path = [ cfg.package pkgs.postgresql ];
environment = env;
serviceConfig = {
Type = "oneshot";
User = cfg.user;
Group = cfg.group;
EnvironmentFile = "/var/lib/mastodon/.secrets_env";
PrivateTmp = true;
LogsDirectory = "mastodon";
StateDirectory = "mastodon";
WorkingDirectory = cfg.package;
};
after = [ "mastodon-init-dirs.service" "network.target" ] ++ (if databaseActuallyCreateLocally then [ "postgresql.service" ] else []);
wantedBy = [ "multi-user.target" ];
};
systemd.services.mastodon-streaming = {
after = [ "network.target" ]
++ (if databaseActuallyCreateLocally then [ "postgresql.service" ] else [])
++ (if cfg.automaticMigrations then [ "mastodon-init-db.service" ] else [ "mastodon-init-dirs.service" ]);
description = "Mastodon streaming";
wantedBy = [ "multi-user.target" ];
environment = env // {
PORT = toString(cfg.streamingPort);
};
serviceConfig = {
ExecStart = "${pkgs.nodejs-slim}/bin/node streaming";
Restart = "always";
RestartSec = 20;
User = cfg.user;
Group = cfg.group;
WorkingDirectory = cfg.package;
EnvironmentFile = "/var/lib/mastodon/.secrets_env";
PrivateTmp = true;
LogsDirectory = "mastodon";
StateDirectory = "mastodon";
};
};
systemd.services.mastodon-web = {
after = [ "network.target" ]
++ (if databaseActuallyCreateLocally then [ "postgresql.service" ] else [])
++ (if cfg.automaticMigrations then [ "mastodon-init-db.service" ] else [ "mastodon-init-dirs.service" ]);
description = "Mastodon web";
wantedBy = [ "multi-user.target" ];
environment = env // {
PORT = toString(cfg.webPort);
};
serviceConfig = {
ExecStart = "${cfg.package}/bin/puma -C config/puma.rb";
Restart = "always";
RestartSec = 20;
User = cfg.user;
Group = cfg.group;
WorkingDirectory = cfg.package;
EnvironmentFile = "/var/lib/mastodon/.secrets_env";
PrivateTmp = true;
LogsDirectory = "mastodon";
StateDirectory = "mastodon";
};
path = with pkgs; [ file imagemagick ffmpeg ];
};
systemd.services.mastodon-sidekiq = {
after = [ "network.target" ]
++ (if databaseActuallyCreateLocally then [ "postgresql.service" ] else [])
++ (if cfg.automaticMigrations then [ "mastodon-init-db.service" ] else [ "mastodon-init-dirs.service" ]);
description = "Mastodon sidekiq";
wantedBy = [ "multi-user.target" ];
environment = env // {
PORT = toString(cfg.sidekiqPort);
};
serviceConfig = {
ExecStart = "${cfg.package}/bin/sidekiq -c 25 -r ${cfg.package}";
Restart = "always";
RestartSec = 20;
User = cfg.user;
Group = cfg.group;
WorkingDirectory = cfg.package;
EnvironmentFile = "/var/lib/mastodon/.secrets_env";
PrivateTmp = true;
LogsDirectory = "mastodon";
StateDirectory = "mastodon";
};
path = with pkgs; [ file imagemagick ffmpeg ];
};
services.nginx = lib.mkIf cfg.configureNginx {
enable = true;
recommendedProxySettings = true; # required for redirections to work
virtualHosts."${cfg.localDomain}" = {
root = "${cfg.package}/public/";
forceSSL = true; # mastodon only supports https
enableACME = true;
locations."/system/".alias = "/var/lib/mastodon/public-system/";
locations."/" = {
tryFiles = "$uri @proxy";
};
locations."@proxy" = {
proxyPass = "http://127.0.0.1:${toString(cfg.webPort)}";
proxyWebsockets = true;
};
locations."/api/v1/streaming/" = {
proxyPass = "http://127.0.0.1:${toString(cfg.streamingPort)}/";
proxyWebsockets = true;
};
};
};
services.postfix = lib.mkIf (cfg.smtp.createLocally && cfg.smtp.host == "127.0.0.1") {
enable = true;
};
services.redis = lib.mkIf (cfg.redis.createLocally && cfg.redis.host == "127.0.0.1") {
enable = true;
};
services.postgresql = lib.mkIf databaseActuallyCreateLocally {
enable = true;
ensureUsers = [
{
name = cfg.database.user;
ensurePermissions."DATABASE ${cfg.database.name}" = "ALL PRIVILEGES";
}
];
ensureDatabases = [ cfg.database.name ];
};
users.users = lib.mkMerge [
(lib.mkIf (cfg.user == "mastodon") {
mastodon = {
isSystemUser = true;
home = cfg.package;
inherit (cfg) group;
};
})
(lib.attrsets.setAttrByPath [ cfg.user "packages" ] [ cfg.package mastodonEnv ])
];
users.groups.mastodon = lib.mkIf (cfg.group == "mastodon") { };
};
meta.maintainers = with lib.maintainers; [ happy-river erictapen ];
}

View File

@ -403,6 +403,10 @@ in
] ++ lib.optional stdenv.isDarwin "--with-iconv-dir=${libiconv}";
};
openssl = attrs: {
buildInputs = [ openssl ];
};
opus-ruby = attrs: {
dontBuild = false;
postPatch = ''

View File

@ -0,0 +1,112 @@
{ lib, stdenv, nodejs-slim, mkYarnPackage, fetchFromGitHub, bundlerEnv
, yarn, callPackage, imagemagick, ffmpeg, file, ruby_2_7
# Allow building a fork or custom version of Mastodon:
, pname ? "mastodon"
, version ? import ./version.nix
, srcOverride ? null
, dependenciesDir ? ./. # Should contain gemset.nix, yarn.nix and package.json.
}:
stdenv.mkDerivation rec {
inherit pname version;
# Using overrideAttrs on src does not build the gems and modules with the overridden src.
# Putting the callPackage up in the arguments list also does not work.
src = if srcOverride != null then srcOverride else callPackage ./source.nix {};
mastodon-gems = bundlerEnv {
name = "${pname}-gems-${version}";
inherit version;
ruby = ruby_2_7;
gemdir = src;
gemset = dependenciesDir + "/gemset.nix";
# This fix (copied from https://github.com/NixOS/nixpkgs/pull/76765) replaces the gem
# symlinks with directories, resolving this error when running rake:
# /nix/store/451rhxkggw53h7253izpbq55nrhs7iv0-mastodon-gems-3.0.1/lib/ruby/gems/2.6.0/gems/bundler-1.17.3/lib/bundler/settings.rb:6:in `<module:Bundler>': uninitialized constant Bundler::Settings (NameError)
postBuild = ''
for gem in "$out"/lib/ruby/gems/*/gems/*; do
cp -a "$gem/" "$gem.new"
rm "$gem"
# needed on macOS, otherwise the mv yields permission denied
chmod +w "$gem.new"
mv "$gem.new" "$gem"
done
'';
};
mastodon-js-modules = mkYarnPackage {
pname = "${pname}-modules";
yarnNix = dependenciesDir + "/yarn.nix";
packageJSON = dependenciesDir + "/package.json";
inherit src version;
};
mastodon-assets = stdenv.mkDerivation {
pname = "${pname}-assets";
inherit src version;
buildInputs = [
mastodon-gems nodejs-slim yarn
];
# FIXME: "production" would require OTP_SECRET to be set, so we use
# development here.
RAILS_ENV = "development";
buildPhase = ''
# Support Mastodon forks which don't call themselves 'mastodon' or which
# omit the organization name from package.json.
if [ "$(ls ${mastodon-js-modules}/libexec/* | grep node_modules)" ]; then
cp -r ${mastodon-js-modules}/libexec/*/node_modules node_modules
else
cp -r ${mastodon-js-modules}/libexec/*/*/node_modules node_modules
fi
chmod -R u+w node_modules
rake webpacker:compile
'';
installPhase = ''
mkdir -p $out/public
cp -r public/assets $out/public
cp -r public/packs $out/public
'';
};
passthru.updateScript = callPackage ./update.nix {};
buildPhase = ''
if [ "$(ls ${mastodon-js-modules}/libexec/* | grep node_modules)" ]; then
ln -s ${mastodon-js-modules}/libexec/*/node_modules node_modules
else
ln -s ${mastodon-js-modules}/libexec/*/*/node_modules node_modules
fi
ln -s ${mastodon-assets}/public/assets public/assets
ln -s ${mastodon-assets}/public/packs public/packs
patchShebangs bin/
for b in $(ls ${mastodon-gems}/bin/)
do
if [ ! -f bin/$b ]; then
ln -s ${mastodon-gems}/bin/$b bin/$b
fi
done
rm -rf log
ln -s /var/log/mastodon log
ln -s /tmp tmp
'';
propagatedBuildInputs = [ imagemagick ffmpeg file mastodon-gems.wrappedRuby ];
installPhase = ''
mkdir -p $out
cp -r * $out/
'';
meta = with lib; {
description = "Self-hosted, globally interconnected microblogging software based on ActivityPub";
homepage = "https://joinmastodon.org";
license = licenses.agpl3Plus;
platforms = [ "x86_64-linux" "i686-linux" ];
maintainers = with maintainers; [ petabyteboy happy-river erictapen ];
};
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,193 @@
{
"version": "3.3.0",
"name": "@tootsuite/mastodon",
"license": "AGPL-3.0-or-later",
"engines": {
"node": ">=10.13"
},
"scripts": {
"postversion": "git push --tags",
"build:development": "cross-env RAILS_ENV=development NODE_ENV=development ./bin/webpack",
"build:production": "cross-env RAILS_ENV=production NODE_ENV=production ./bin/webpack",
"manage:translations": "node ./config/webpack/translationRunner.js",
"start": "node ./streaming/index.js",
"test": "${npm_execpath} run test:lint:js && ${npm_execpath} run test:jest",
"test:lint": "${npm_execpath} run test:lint:js && ${npm_execpath} run test:lint:sass",
"test:lint:js": "eslint --ext=js . --cache",
"test:lint:sass": "sass-lint -v",
"test:jest": "cross-env NODE_ENV=test jest --coverage"
},
"repository": {
"type": "git",
"url": "https://github.com/tootsuite/mastodon.git"
},
"browserslist": [
"last 2 versions",
"IE >= 11",
"iOS >= 9",
"not dead"
],
"jest": {
"projects": [
"<rootDir>/app/javascript/mastodon"
],
"testPathIgnorePatterns": [
"<rootDir>/node_modules/",
"<rootDir>/vendor/",
"<rootDir>/config/",
"<rootDir>/log/",
"<rootDir>/public/",
"<rootDir>/tmp/"
],
"setupFiles": [
"raf/polyfill"
],
"setupFilesAfterEnv": [
"<rootDir>/app/javascript/mastodon/test_setup.js"
],
"collectCoverageFrom": [
"app/javascript/mastodon/**/*.js",
"!app/javascript/mastodon/features/emoji/emoji_compressed.js",
"!app/javascript/mastodon/locales/locale-data/*.js",
"!app/javascript/mastodon/service_worker/entry.js",
"!app/javascript/mastodon/test_setup.js"
],
"coverageDirectory": "<rootDir>/coverage",
"moduleDirectories": [
"<rootDir>/node_modules",
"<rootDir>/app/javascript"
]
},
"private": true,
"dependencies": {
"@babel/core": "^7.12.7",
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-proposal-decorators": "^7.12.1",
"@babel/plugin-transform-react-inline-elements": "^7.12.1",
"@babel/plugin-transform-runtime": "^7.12.1",
"@babel/preset-env": "^7.12.7",
"@babel/preset-react": "^7.12.7",
"@babel/runtime": "^7.12.5",
"@clusterws/cws": "^3.0.0",
"@gamestdio/websocket": "^0.3.2",
"@github/webauthn-json": "^0.5.7",
"@rails/ujs": "^6.0.3",
"array-includes": "^3.1.1",
"arrow-key-navigation": "^1.2.0",
"autoprefixer": "^9.8.6",
"axios": "^0.21.0",
"babel-loader": "^8.2.1",
"babel-plugin-lodash": "^3.3.4",
"babel-plugin-preval": "^5.0.0",
"babel-plugin-react-intl": "^6.2.0",
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
"babel-runtime": "^6.26.0",
"blurhash": "^1.1.3",
"classnames": "^2.2.5",
"color-blend": "^3.0.0",
"compression-webpack-plugin": "^6.1.1",
"cross-env": "^7.0.2",
"css-loader": "^5.0.1",
"cssnano": "^4.1.10",
"detect-passive-events": "^2.0.1",
"dotenv": "^8.2.0",
"emoji-mart": "Gargron/emoji-mart#build",
"es6-symbol": "^3.1.3",
"escape-html": "^1.0.3",
"exif-js": "^2.3.0",
"express": "^4.17.1",
"file-loader": "^6.2.0",
"font-awesome": "^4.7.0",
"glob": "^7.1.6",
"history": "^4.10.1",
"http-link-header": "^1.0.3",
"immutable": "^3.8.2",
"imports-loader": "^1.2.0",
"intersection-observer": "^0.11.0",
"intl": "^1.2.5",
"intl-messageformat": "^2.2.0",
"intl-relativeformat": "^6.4.3",
"is-nan": "^1.3.0",
"js-yaml": "^3.13.1",
"lodash": "^4.17.19",
"mark-loader": "^0.1.6",
"marky": "^1.2.1",
"mini-css-extract-plugin": "^1.3.1",
"mkdirp": "^1.0.4",
"npmlog": "^4.1.2",
"object-assign": "^4.1.1",
"object-fit-images": "^3.2.3",
"object.values": "^1.1.1",
"offline-plugin": "^5.0.7",
"path-complete-extname": "^1.0.0",
"pg": "^6.4.0",
"postcss-loader": "^3.0.0",
"postcss-object-fit-images": "^1.1.2",
"promise.prototype.finally": "^3.1.2",
"prop-types": "^15.5.10",
"punycode": "^2.1.0",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"react-hotkeys": "^1.1.4",
"react-immutable-proptypes": "^2.2.0",
"react-immutable-pure-component": "^2.2.2",
"react-intl": "^2.9.0",
"react-masonry-infinite": "^1.2.2",
"react-motion": "^0.5.2",
"react-notification": "^6.8.5",
"react-overlays": "^0.9.2",
"react-redux": "^7.2.2",
"react-redux-loading-bar": "^4.0.8",
"react-router-dom": "^4.1.1",
"react-router-scroll-4": "^1.0.0-beta.1",
"react-select": "^3.1.0",
"react-sparklines": "^1.7.0",
"react-swipeable-views": "^0.13.9",
"react-textarea-autosize": "^8.3.0",
"react-toggle": "^4.1.1",
"redis": "^3.0.2",
"redux": "^4.0.5",
"redux-immutable": "^4.0.0",
"redux-thunk": "^2.2.0",
"regenerator-runtime": "^0.13.7",
"rellax": "^1.12.1",
"requestidlecallback": "^0.3.0",
"reselect": "^4.0.0",
"rimraf": "^3.0.2",
"sass": "^1.29.0",
"sass-loader": "^10.1.0",
"stacktrace-js": "^2.0.2",
"stringz": "^2.1.0",
"substring-trie": "^1.0.2",
"terser-webpack-plugin": "^4.2.3",
"tesseract.js": "^2.1.1",
"throng": "^4.0.0",
"tiny-queue": "^0.2.1",
"uuid": "^8.3.1",
"webpack": "^4.44.2",
"webpack-assets-manifest": "^3.1.1",
"webpack-bundle-analyzer": "^4.1.0",
"webpack-cli": "^3.3.12",
"webpack-merge": "^5.4.0",
"wicg-inert": "^3.1.0",
"kind-of": "^6.0.3"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.11.6",
"@testing-library/react": "^11.2.2",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.6.3",
"eslint": "^7.14.0",
"eslint-plugin-import": "~2.22.1",
"eslint-plugin-jsx-a11y": "~6.4.1",
"eslint-plugin-promise": "~4.2.1",
"eslint-plugin-react": "~7.21.5",
"jest": "^26.6.3",
"raf": "^3.4.1",
"react-intl-translations-manager": "^5.0.3",
"react-test-renderer": "^16.14.0",
"sass-lint": "^1.13.1",
"webpack-dev-server": "^3.11.0",
"yargs": "^16.1.1"
}
}

View File

@ -0,0 +1,67 @@
diff --git a/package.json b/package.json
index 7b8f49dd8..24cdd3498 100644
--- a/package.json
+++ b/package.json
@@ -168,7 +168,8 @@
"webpack-bundle-analyzer": "^4.1.0",
"webpack-cli": "^3.3.12",
"webpack-merge": "^5.4.0",
- "wicg-inert": "^3.1.0"
+ "wicg-inert": "^3.1.0",
+ "kind-of": "^6.0.3"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.11.6",
@@ -187,8 +188,5 @@
"sass-lint": "^1.13.1",
"webpack-dev-server": "^3.11.0",
"yargs": "^16.1.1"
- },
- "resolutions": {
- "kind-of": "^6.0.3"
}
}
diff --git a/yarn.lock b/yarn.lock
index 4aa8f6380..68d2fd8b5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5689,6 +5689,11 @@ is-binary-path@~2.1.0:
dependencies:
binary-extensions "^2.0.0"
+is-buffer@^1.1.5:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
+ integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
+
is-callable@^1.1.4, is-callable@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9"
@@ -6639,7 +6644,26 @@ killable@^1.0.1:
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==
-kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0, kind-of@^4.0.0, kind-of@^5.0.0, kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3:
+kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
+ integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
+ integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc=
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^5.0.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
+ integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
+
+kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3:
version "6.0.3"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==

View File

@ -0,0 +1,11 @@
# This file was generated by pkgs.mastodon.updateScript.
{ fetchgit, applyPatches }: let
src = fetchgit {
url = "https://github.com/tootsuite/mastodon.git";
rev = "v3.3.0";
sha256 = "17wvggvy5mmyf3f1i5v1hgvh6wjdhg9hb3wiyfaydx0slsg03qba";
};
in applyPatches {
inherit src;
patches = [./resolutions.patch ./version.patch ];
}

View File

@ -0,0 +1,21 @@
{ pkgs, stdenv, lib, makeWrapper, yarn2nix, bundix, coreutils,
diffutils, nix-prefetch-github, gnused, jq }:
stdenv.mkDerivation rec {
name = "mastodon-update-script";
installPhase = ''
mkdir -p $out/bin
cp ${./update.sh} $out/bin/update.sh
patchShebangs $out/bin/update.sh
wrapProgram $out/bin/update.sh --prefix PATH : ${lib.makeBinPath buildInputs}
'';
phases = [ "installPhase" ];
nativeBuildInputs = [ makeWrapper ];
buildInputs = [ yarn2nix bundix coreutils diffutils nix-prefetch-github gnused jq ];
meta = {
maintainers = with lib.maintainers; [ happy-river ];
description = "Utility to generate Nix expressions for Mastodon's dependencies";
platforms = lib.platforms.unix;
};
}

121
pkgs/servers/mastodon/update.sh Executable file
View File

@ -0,0 +1,121 @@
#!/usr/bin/env bash
set -e
URL=https://github.com/tootsuite/mastodon.git
POSITIONAL=()
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
--url)
URL="$2"
shift # past argument
shift # past value
;;
--ver)
VERSION="$2"
shift # past argument
shift # past value
;;
--rev)
REVISION="$2"
shift # past argument
shift # past value
;;
--patches)
PATCHES="$2"
shift # past argument
shift # past value
;;
*) # unknown option
POSITIONAL+=("$1")
shift # past argument
;;
esac
done
if [[ -z "$VERSION" || -n "$POSITIONAL" ]]; then
echo "Usage: update.sh [--url URL] --ver VERSION [--rev REVISION] [--patches PATCHES]"
echo "URL may be any path acceptable to 'git clone' and VERSION the"
echo "semantic version number. If VERSION is not a revision acceptable to"
echo "'git checkout', you must provide one in REVISION. If URL is not"
echo "provided, it defaults to https://github.com/tootsuite/mastodon.git."
echo "PATCHES, if provided, should be one or more Nix expressions"
echo "separated by spaces."
exit 1
fi
if [[ -z "$REVISION" ]]; then
REVISION="$VERSION"
fi
rm -f gemset.nix yarn.nix version.nix version.patch source.nix package.json
TARGET_DIR="$PWD"
WORK_DIR=$(mktemp -d)
# Check that working directory was created.
if [[ ! "$WORK_DIR" || ! -d "$WORK_DIR" ]]; then
echo "Could not create temporary directory"
exit 1
fi
# Delete the working directory on exit.
function cleanup {
# Report errors, if any, from nix-prefetch-git
grep "fatal" $WORK_DIR/nix-prefetch-git.out >/dev/stderr || true
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
echo "Fetching source code $REVISION from $URL"
JSON=$(nix-prefetch-git --url "$URL" --rev "$REVISION" 2> $WORK_DIR/nix-prefetch-git.out)
SHA=$(echo $JSON | jq -r .sha256)
FETCHED_SOURCE_DIR=$(grep '^path is' $WORK_DIR/nix-prefetch-git.out | sed 's/^path is //')
echo "Creating version.nix"
echo \"$VERSION\" | sed 's/^"v/"/' > version.nix
echo "Creating source.nix"
# yarn2nix and mkYarnPackage want the version to be present in
# package.json. Mastodon itself does not include the version in
# package.json but at least one fork (Soapbox) does.
if [ $(jq .version $FETCHED_SOURCE_DIR/package.json) == "null" ]; then
mkdir $WORK_DIR/a $WORK_DIR/b
cp $FETCHED_SOURCE_DIR/package.json $WORK_DIR/a
cd $WORK_DIR
jq "{version:$(cat $TARGET_DIR/version.nix)} + ." a/package.json > b/package.json
diff -Naur --label a/package.json --label b/package.json a b > $TARGET_DIR/version.patch || true
rm -rf a b tmp
cd $TARGET_DIR
PATCHES="$PATCHES ./version.patch "
fi
cat > source.nix << EOF
# This file was generated by pkgs.mastodon.updateScript.
{ fetchgit, applyPatches }: let
src = fetchgit {
url = "$URL";
rev = "$REVISION";
sha256 = "$SHA";
};
in applyPatches {
inherit src;
patches = [$PATCHES];
}
EOF
SOURCE_DIR="$(nix-build --no-out-link -E '(import <nixpkgs> {}).callPackage ./source.nix {}')"
echo "Creating gemset.nix"
bundix --lockfile="$SOURCE_DIR/Gemfile.lock" --gemfile="$SOURCE_DIR/Gemfile"
echo "" >> $TARGET_DIR/gemset.nix # Create trailing newline to please EditorConfig checks
echo "Creating yarn.nix"
cp -r $SOURCE_DIR/* $WORK_DIR
chmod -R u+w $WORK_DIR
cd $WORK_DIR
yarn2nix > $TARGET_DIR/yarn.nix
sed "s/https___.*_//g" -i $TARGET_DIR/yarn.nix
cp $WORK_DIR/package.json $TARGET_DIR

View File

@ -0,0 +1 @@
"3.3.0"

View File

@ -0,0 +1,9 @@
diff -Naur --label a/package.json --label b/package.json a/package.json b/package.json
--- a/package.json
+++ b/package.json
@@ -1,4 +1,5 @@
{
+ "version": "3.3.0",
"name": "@tootsuite/mastodon",
"license": "AGPL-3.0-or-later",
"engines": {

12181
pkgs/servers/mastodon/yarn.nix Normal file

File diff suppressed because it is too large Load Diff

View File

@ -17892,6 +17892,8 @@ in
mailman-web = with python3.pkgs; toPythonApplication mailman-web;
mastodon = callPackage ../servers/mastodon { };
mattermost = callPackage ../servers/mattermost { };
matterircd = callPackage ../servers/mattermost/matterircd.nix { };
matterbridge = callPackage ../servers/matterbridge { };