diff --git a/.github/problem-matchers/generic.json b/.github/problem-matchers/generic.json index 83bf46ea4..d26773421 100644 --- a/.github/problem-matchers/generic.json +++ b/.github/problem-matchers/generic.json @@ -4,7 +4,7 @@ "owner": "generic", "pattern": [ { - "regexp": "^([^\\s:]+):(\\d+)(?::(\\d+))?:?\\s+(?:((?i)warning|error):?)?\\s*(.+)$", + "regexp": "^(?:\\.\\./)?([^\\s:]+):(\\d+)(?::(\\d+))?:?\\s+(?:((?i)warning|error):?)?\\s*(.+)$", "file": 1, "line": 2, "column": 3, @@ -17,7 +17,7 @@ "owner": "generic-nolocation", "pattern": [ { - "regexp": "^(?:([^\\s:]+):?\\s+)?((?i)warning|error):?\\s*(.+)$", + "regexp": "^(?:\\.\\./)?(?:([^\\s:]+):?\\s+)?((?i)warning|error):?\\s*(.+)$", "file": 1, "severity": 2, "message": 3 diff --git a/.github/problem-matchers/gettext-stats.json b/.github/problem-matchers/gettext-stats.json index ed6034a50..ec2c73ff7 100644 --- a/.github/problem-matchers/gettext-stats.json +++ b/.github/problem-matchers/gettext-stats.json @@ -5,7 +5,7 @@ "severity": "warning", "pattern": [ { - "regexp": "msgfmt .* --statistics .* (po/.*\\.po)", + "regexp": "(?:^|\\s)(?:\\.\\./)?(locale/.*\\.po)$", "file": 1 }, { diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e380769e3..5744c0538 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,11 +44,11 @@ jobs: - name: Install JS dependencies id: npm - run: npm ci + run: npm install if: ${{ always() && steps.checkout.conclusion == 'success' }} - name: Lint JS code - run: make "ESLINT_OPTS=--format .github/eslint-formatter.js" lint + run: npm run-script lint -- --format .github/eslint-formatter.js if: ${{ always() && steps.npm.conclusion == 'success' }} - name: Pre-create pip cache directory @@ -75,15 +75,28 @@ jobs: run: echo "::add-matcher::.github/problem-matchers/generic.json" if: ${{ always() && steps.checkout.conclusion == 'success' }} - - name: Compile GSettings schemas - run: make schemas 2>&1 | tee schemas.log - shell: bash + - id: meson-setup + name: Prepare build directory + run: meson setup build if: ${{ always() && steps.checkout.conclusion == 'success' }} - - name: Validate Gtk .ui files - run: xvfb-run make gtk-builder-validate 2>&1 | tee gtk-builder.log + - name: Run glib-compile-schemas checks + run: meson test -v --suite glib-compile-schemas --logbase glib-compile-schemas + working-directory: build shell: bash - if: ${{ always() && steps.checkout.conclusion == 'success' }} + if: ${{ always() && steps.meson-setup.conclusion == 'success' }} + + - name: Run desktop-file-validate checks + run: meson test -v --suite desktop-file-validate --logbase desktop-file-validate + working-directory: build + shell: bash + if: ${{ always() && steps.meson-setup.conclusion == 'success' }} + + - name: Run gtk-builder-tool checks + run: xvfb-run meson test -v --suite gtk-builder-validate --logbase gtk-builder-validate + working-directory: build + shell: bash + if: ${{ always() && steps.meson-setup.conclusion == 'success' }} - name: Ensure Python requirements .txt files are in sync with .in files run: | @@ -102,7 +115,7 @@ jobs: if: ${{ always() && steps.checkout.conclusion == 'success' }} - name: Upload reports to Testspace - run: testspace --verbose eslint.xml "*.log{lint}" + run: testspace --verbose eslint.xml "build/*.log{lint}" "build/meson-logs/*.txt{lint}" if: ${{ always() && steps.setup_testspace.outcome == 'success' }} pack: @@ -119,13 +132,17 @@ jobs: - name: Enable generic error matcher run: echo "::add-matcher::.github/problem-matchers/generic.json" + - name: Prepare build directory + run: meson setup build + - name: Build extension package - run: xvfb-run make ONLY_RELEASE_LOCALES=true pack + run: xvfb-run ninja -j1 pack + working-directory: build - name: Upload extension package as artifact id: upload uses: actions/upload-artifact@v4 with: name: pack - path: "*.shell-extension.zip" + path: "build/*.shell-extension.zip" if-no-files-found: error diff --git a/.github/workflows/check-po.yml b/.github/workflows/check-po.yml index 66f656871..84ec72844 100644 --- a/.github/workflows/check-po.yml +++ b/.github/workflows/check-po.yml @@ -4,7 +4,6 @@ on: env: FORCE_COLOR: 1 - PIP_DISABLE_PIP_VERSION_CHECK: 1 jobs: configure: @@ -23,7 +22,7 @@ jobs: echo -n linguas= >>$GITHUB_OUTPUT grep -Ev '^\s*#.*' LINGUAS | jq -Rcn '[inputs | scan("\\S+")]' >>$GITHUB_OUTPUT shell: bash - working-directory: po + working-directory: locale check: needs: configure @@ -39,27 +38,26 @@ jobs: steps: - name: Checkout - id: checkout uses: actions/checkout@v4 - run: git config --global --replace-all safe.directory "$GITHUB_WORKSPACE" - - name: Enable gettext stats problem matcher - run: echo "::add-matcher::.github/problem-matchers/gettext-stats.json" - - name: Enable generic problem matcher run: echo "::add-matcher::.github/problem-matchers/generic.json" + - name: Enable gettext stats problem matcher + run: echo "::add-matcher::.github/problem-matchers/gettext-stats.json" + - name: Compile translation - run: make msgfmt/${{ matrix.lang }} 2>&1 | tee $GITHUB_STEP_SUMMARY + run: | + echo locale/${{ matrix.lang }}.po + msgfmt --check -v -o /dev/null locale/${{ matrix.lang }}.po 2>&1 | tee $GITHUB_STEP_SUMMARY shell: bash - name: Disable gettext stats problem matcher run: echo "::remove-matcher owner=gettext-stats::" - name: Ensure .po file is in sync with .pot - run: | - touch po/*.pot # Make sure .pot won't be re-generated - make msgcmp/${{ matrix.lang }} 2>&1 + run: msgcmp --use-untranslated --use-fuzzy locale/${{ matrix.lang }}.po locale/*.pot shell: bash - if: ${{ always() && steps.checkout.conclusion == 'success' }} + if: ${{ always() && steps.meson-setup.conclusion == 'success' }} diff --git a/.github/workflows/pot.yml b/.github/workflows/pot.yml index 880782287..a0f79fdcc 100644 --- a/.github/workflows/pot.yml +++ b/.github/workflows/pot.yml @@ -1,20 +1,26 @@ -concurrency: - group: ${{ github.workflow }}/${{ github.ref }} - -name: pot - on: workflow_dispatch: + inputs: + commit: + description: Commit changes + required: false + default: false + type: boolean + workflow_call: - push: - branches: - - master - paths-ignore: - - docs/** - - po/*.po - - README.md - - Vagrantfile - - vagrant-provision/** + inputs: + commit: + description: Commit changes + required: false + default: false + type: boolean + secrets: + APP_ID: + description: 'ID of the committer application' + required: false + APP_KEY: + description: 'Private key of the committer application' + required: false jobs: pot: @@ -23,28 +29,31 @@ jobs: image: ghcr.io/ddterm/ci-docker-image:meson steps: - - name: Get app token - id: app-token - uses: actions/create-github-app-token@v1 - with: - app-id: ${{ secrets.APP_ID }} - private-key: ${{ secrets.APP_KEY }} - - name: Checkout uses: actions/checkout@v4 - with: - token: ${{ steps.app-token.outputs.token }} - run: git config --global --replace-all safe.directory "$GITHUB_WORKSPACE" - name: Enable generic error matcher run: echo "::add-matcher::.github/problem-matchers/generic.json" - - name: Update .pot files - run: po/update-pot.sh + - name: Prepare build directory + run: meson setup build + + - name: Update POTFILES.in + run: ninja -j1 potfiles + working-directory: build + + - name: Update .pot file + run: ninja -j1 msgmerge + working-directory: build + + - name: Update .po files + run: for pofile in *.po; do msgmerge --update --previous "$pofile" *.pot; done + working-directory: po - name: Stage changes - run: git add po/*.po po/*.pot + run: git add po/*.po po/*.pot po/POTFILES.in - name: Check if there are any changes id: diff @@ -52,12 +61,20 @@ jobs: with: result-encoding: string script: | - const { stdout } = await exec.getExecOutput('git', ['diff', '--cached']); + const { stdout } = await exec.getExecOutput('git', ['diff', '--cached', '--ignore-matching-lines=^"POT-Creation-Date: ']); return stdout.trim(); + - name: Get commit token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_KEY }} + if: inputs.commit + - name: Commit uses: ddterm/github-api-commit-action@ccf9b520c5698380ad3b9619c5add427369b7ef1 - if: steps.diff.outputs.result != '' with: token: ${{ steps.app-token.outputs.token }} commit-message: 'Update translation files' + if: inputs.commit && steps.diff.outputs.result diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 28bf243af..c14b109fe 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -6,7 +6,10 @@ on: pull_request: paths-ignore: - docs/** - - po/** + - po/*.po + - po/*.pot + - po/POTFILES + - po/POTFILES.in - README.md - Vagrantfile - vagrant-provision/** @@ -24,3 +27,9 @@ jobs: test: needs: build uses: ./.github/workflows/test.yml + + translations: + uses: ./.github/workflows/pot.yml + with: + commit: false + secrets: inherit diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 429149d72..c8e45f76d 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -12,7 +12,10 @@ on: - v* paths-ignore: - docs/** - - po/** + - po/*.po + - po/*.pot + - po/POTFILES + - po/POTFILES.in - README.md - Vagrantfile - vagrant-provision/** @@ -26,3 +29,9 @@ jobs: test: needs: build uses: ./.github/workflows/test.yml + + translations: + uses: ./.github/workflows/pot.yml + with: + commit: ${{ github.ref_type == 'branch' && github.ref_name == github.event.repository.default_branch }} + secrets: inherit diff --git a/.gitignore b/.gitignore index ef8801700..951e52c31 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,6 @@ *~ -/node_modules/ -# Makefile output -/*.shell-extension.zip -/ddterm/pref/ui/ -/ddterm/com.github.amezin.ddterm.desktop -/ddterm/com.github.amezin.ddterm.desktop.in -/ddterm/com.github.amezin.ddterm.service -/metadata.json -/schemas/gschemas.compiled -/locale/ -/tmp/ -/revision.txt +/node_modules/ # do-in-docker.sh/do-in-podman.sh /.container-home/ diff --git a/Makefile b/Makefile deleted file mode 100755 index dae82623c..000000000 --- a/Makefile +++ /dev/null @@ -1,500 +0,0 @@ -#!/usr/bin/env -S make -f - -# See docs/BUILD.md - -SHELL := /bin/bash - -EXTENSION_UUID := ddterm@amezin.github.com - -TRUE_VALUES := yes YES true TRUE on ON 1 -is-true = $(filter 1,$(words $(filter $(TRUE_VALUES),$(1)))) - -all: -.PHONY: all - -find-tool = $(or $(shell command -v $(1)),tool-not-found/$(1)) - -define tool-not-found-message -$* not found and is required. -You could use do-in-docker.sh or do-in-podman.sh to avoid installing build dependencies. -Please check docs/BUILD.md -endef - -tool-not-found/%: - $(error $(tool-not-found-message)) - -CLEAN := -TRANSLATABLE_SOURCES := -PACK_CONTENT := - -# Git revision file - -ifeq ($(file $@ - -else - -revision.txt: revision.txt.in - cat $< >$@ - -endif - -CLEAN += revision.txt -PACK_CONTENT += revision.txt - -# GSettings schemas - -SCHEMAS := $(wildcard schemas/*.gschema.xml) -SCHEMAS_COMPILED := schemas/gschemas.compiled -SCHEMAS_ALL := $(SCHEMAS) $(SCHEMAS_COMPILED) - -GLIB_COMPILE_SCHEMAS := $(call find-tool,glib-compile-schemas) - -$(SCHEMAS_COMPILED): $(SCHEMAS) $(GLIB_COMPILE_SCHEMAS) - $(GLIB_COMPILE_SCHEMAS) --strict $(dir $@) - -CLEAN += $(SCHEMAS_COMPILED) -PACK_CONTENT += $(SCHEMAS) - -schemas: $(SCHEMAS_COMPILED) -.PHONY: schemas -all: schemas - -# Locales - -LINGUAS_FILE := po/LINGUAS -LOCALES_RELEASE := cs de el fr it nb_NO pl pt ru zh_CN -LOCALE_SOURCE_PATTERN := po/%.po -LOCALES_ALL := $(shell grep -Ev '^\s*#.*' $(LINGUAS_FILE)) - -ONLY_RELEASE_LOCALES := no - -ifeq ($(call is-true,$(ONLY_RELEASE_LOCALES)),1) -LOCALES := $(LOCALES_RELEASE) -else -LOCALES := $(LOCALES_ALL) -endif - -LOCALE_COMPILED_PATTERN := locale/%/LC_MESSAGES/$(EXTENSION_UUID).mo -LOCALES_COMPILED := $(patsubst %,$(LOCALE_COMPILED_PATTERN),$(LOCALES)) - -MSGFMT := $(call find-tool,msgfmt) - -$(LOCALES_COMPILED): $(LOCALE_COMPILED_PATTERN): $(LOCALE_SOURCE_PATTERN) $(MSGFMT) - mkdir -p $(dir $@) - $(MSGFMT) --check --strict --statistics -o $@ $< - -$(addprefix msgfmt/,$(LOCALES)): msgfmt/%: $(LOCALE_COMPILED_PATTERN) - -CLEAN += $(LOCALES_COMPILED) -PACK_CONTENT += $(LOCALES_COMPILED) - -locales msgfmt: $(LOCALES_COMPILED) -.PHONY: locales msgfmt - -# Glade UI - -PREFS_GLADE_UI := $(wildcard ddterm/pref/glade/*.ui) -PREFS_GLADE_UI_PATTERN := ddterm/pref/glade/%.ui -TRANSLATABLE_SOURCES += $(APP_GLADE_UI) $(PREFS_GLADE_UI) - -ddterm/pref/ui: - mkdir -p $@ - -# Gtk 3 .ui - -GTK_BUILDER_TOOL := $(call find-tool,gtk-builder-tool) - -ddterm/pref/ui/gtk3: | ddterm/pref/ui - mkdir -p $@ - -PREFS_UI_GTK3_PATTERN := ddterm/pref/ui/gtk3/%.ui -PREFS_UI_GTK3 := $(patsubst $(PREFS_GLADE_UI_PATTERN),$(PREFS_UI_GTK3_PATTERN),$(PREFS_GLADE_UI)) - -$(PREFS_UI_GTK3): $(PREFS_UI_GTK3_PATTERN): $(PREFS_GLADE_UI_PATTERN) $(GTK_BUILDER_TOOL) | ddterm/pref/ui/gtk3 - $(GTK_BUILDER_TOOL) simplify $< >$@ - -GTK3_GENERATED_UI := $(APP_UI) $(PREFS_UI_GTK3) -GTK3_HANDCRAFTED_UI := ddterm/app/menus.ui -GTK3_UI := $(GTK3_GENERATED_UI) $(GTK3_HANDCRAFTED_UI) - -CLEAN += $(GTK3_GENERATED_UI) -PACK_CONTENT += $(GTK3_UI) -TRANSLATABLE_SOURCES += $(GTK3_HANDCRAFTED_UI) - -# Gtk 4 .ui - -GTK4_BUILDER_TOOL := $(call find-tool,gtk4-builder-tool) -XSLTPROC := $(call find-tool,xsltproc) - -ddterm/pref/ui/gtk4 ddterm/pref/ui/gtk4/3to4-fixup ddterm/pref/ui/gtk4/3to4: - mkdir -p $@ - -ddterm/pref/ui/gtk4/3to4-fixup ddterm/pref/ui/gtk4/3to4: | ddterm/pref/ui/gtk4 - -PREFS_UI_3TO4_FIXUP_PATTERN := ddterm/pref/ui/gtk4/3to4-fixup/%.ui -PREFS_UI_3TO4_FIXUP := $(patsubst $(PREFS_GLADE_UI_PATTERN),$(PREFS_UI_3TO4_FIXUP_PATTERN),$(PREFS_GLADE_UI)) - -$(PREFS_UI_3TO4_FIXUP): $(PREFS_UI_3TO4_FIXUP_PATTERN): $(PREFS_GLADE_UI_PATTERN) ddterm/pref/glade/3to4-fixup.xsl $(XSLTPROC) | ddterm/pref/ui/gtk4/3to4-fixup - $(XSLTPROC) ddterm/pref/glade/3to4-fixup.xsl $< >$@ - -PREFS_UI_3TO4_PATTERN := ddterm/pref/ui/gtk4/3to4/%.ui -PREFS_UI_3TO4 := $(patsubst $(PREFS_UI_3TO4_FIXUP_PATTERN),$(PREFS_UI_3TO4_PATTERN),$(PREFS_UI_3TO4_FIXUP)) - -$(PREFS_UI_3TO4): $(PREFS_UI_3TO4_PATTERN): $(PREFS_UI_3TO4_FIXUP_PATTERN) $(GTK4_BUILDER_TOOL) | ddterm/pref/ui/gtk4/3to4 - $(GTK4_BUILDER_TOOL) simplify --3to4 $< >$@ - -PREFS_UI_GTK4_PATTERN := ddterm/pref/ui/gtk4/%.ui -PREFS_UI_GTK4 := $(patsubst $(PREFS_UI_3TO4_PATTERN),$(PREFS_UI_GTK4_PATTERN),$(PREFS_UI_3TO4)) - -$(PREFS_UI_GTK4): $(PREFS_UI_GTK4_PATTERN): $(PREFS_UI_3TO4_PATTERN) $(GTK4_BUILDER_TOOL) | ddterm/pref/ui/gtk4 - $(GTK4_BUILDER_TOOL) simplify $< >$@ - -CLEAN += $(PREFS_UI_3TO4_FIXUP) $(PREFS_UI_3TO4) $(PREFS_UI_GTK4) - -GTK4_UI := $(PREFS_UI_GTK4) - -PACK_CONTENT += $(GTK4_UI) - -# metadata.json - -# Prevent people from trying to feed source archives to 'gnome-extensions install'. -# https://github.com/ddterm/gnome-shell-extension-ddterm/issues/61 - -metadata.json: metadata.json.in - cp $< $@ - -PACK_CONTENT += metadata.json -CLEAN += metadata.json - -# JS sources - -JS_SOURCE_WILDCARDS := \ - *.js \ - ddterm/*.js \ - ddterm/app/*.js \ - ddterm/backport/*.js \ - ddterm/pref/*.js \ - ddterm/shell/*.js \ - ddterm/util/*.js \ - misc/*.js \ - -JS_SOURCES := $(wildcard $(JS_SOURCE_WILDCARDS)) -LAUNCHER := bin/com.github.amezin.ddterm -EXECUTABLES := $(LAUNCHER) - -TRANSLATABLE_SOURCES += $(JS_SOURCES) -PACK_CONTENT += $(EXECUTABLES) $(filter-out $(EXECUTABLES),$(JS_SOURCES)) - -# .desktop entry - -UNTRANSLATED_DESKTOP_ENTRY := ddterm/com.github.amezin.ddterm.desktop.in.in -TRANSLATABLE_SOURCES += $(UNTRANSLATED_DESKTOP_ENTRY) - -UNCONFIGURED_DESKTOP_ENTRY := $(basename $(UNTRANSLATED_DESKTOP_ENTRY)) - -$(UNCONFIGURED_DESKTOP_ENTRY): $(UNTRANSLATED_DESKTOP_ENTRY) $(MSGFMT) - $(MSGFMT) --desktop -o $@ --template=$< -d po - -$(UNCONFIGURED_DESKTOP_ENTRY): $(patsubst %,$(LOCALE_SOURCE_PATTERN),$(LOCALES)) -$(UNCONFIGURED_DESKTOP_ENTRY): $(LINGUAS_FILE) - -$(UNCONFIGURED_DESKTOP_ENTRY): export LINGUAS := $(LOCALES) - -CLEAN += $(UNCONFIGURED_DESKTOP_ENTRY) - -UNCONFIGURED_DBUS_SERVICE := ddterm/com.github.amezin.ddterm.service.in - -# package - -PACK_CONTENT += \ - ddterm/app/style.css \ - ddterm/app/dependencies.json \ - $(wildcard ddterm/app/icons/*) \ - ddterm/com.github.amezin.ddterm.Extension.xml \ - ddterm/com.github.amezin.ddterm.HeapDump.xml \ - $(UNCONFIGURED_DESKTOP_ENTRY) \ - $(UNCONFIGURED_DBUS_SERVICE) \ - LICENSE \ - -PACK_CONTENT := $(sort $(PACK_CONTENT)) - -build: $(PACK_CONTENT) -.PHONY: build - -ZIP := $(call find-tool,zip) - -EXTENSION_PACK := $(EXTENSION_UUID).shell-extension.zip -$(EXTENSION_PACK): $(PACK_CONTENT) $(ZIP) $(LINGUAS_FILE) - $(RM) $@ - $(ZIP) -y -nw $@ -- $(PACK_CONTENT) - -pack: $(EXTENSION_PACK) -.PHONY: pack - -all: pack -CLEAN += $(EXTENSION_PACK) - -# install/uninstall package - user - -user-install: $(EXTENSION_PACK) develop-uninstall - gnome-extensions install -f $< - -user-uninstall: develop-uninstall - gnome-extensions uninstall $(EXTENSION_UUID) - -.PHONY: user-install user-uninstall - -# install/uninstall package - system-wide - -# https://www.gnu.org/software/make/manual/html_node/Command-Variables.html -INSTALL := install -INSTALL_PROGRAM := $(INSTALL) -INSTALL_DATA := $(INSTALL) -m 644 - -# https://www.gnu.org/software/make/manual/html_node/Directory-Variables.html -prefix := /usr -exec_prefix := $(prefix) -datarootdir := $(prefix)/share -datadir := $(datarootdir) -bindir := $(exec_prefix)/bin - -extensiondir := $(datadir)/gnome-shell/extensions - -CONFIGURED_DESKTOP_ENTRY := $(basename $(UNCONFIGURED_DESKTOP_ENTRY)) -CONFIGURED_DBUS_SERVICE := $(basename $(UNCONFIGURED_DBUS_SERVICE)) - -SYS_INSTALLED_EXTENSION_DIR := $(extensiondir)/$(EXTENSION_UUID) -SYS_INSTALLED_CONTENT := $(addprefix $(SYS_INSTALLED_EXTENSION_DIR)/,$(filter-out $(SCHEMAS_ALL),$(PACK_CONTENT))) -SYS_INSTALLED_SCHEMAS := $(addprefix $(datadir)/glib-2.0/,$(SCHEMAS)) -SYS_INSTALLED_DESKTOP_ENTRY := $(datadir)/applications/$(notdir $(CONFIGURED_DESKTOP_ENTRY)) -SYS_INSTALLED_DBUS_SERVICE := $(datadir)/dbus-1/services/$(notdir $(CONFIGURED_DBUS_SERVICE)) -SYS_INSTALLED_EXECUTABLES := $(addprefix $(SYS_INSTALLED_EXTENSION_DIR)/,$(EXECUTABLES)) -SYS_INSTALLED_LAUNCHER := $(filter %$(LAUNCHER),$(SYS_INSTALLED_EXECUTABLES)) -SYS_INSTALLED_LAUNCHER_SYMLINK := $(bindir)/$(notdir $(LAUNCHER)) -SYS_INSTALLED_ALL := \ - $(SYS_INSTALLED_CONTENT) \ - $(SYS_INSTALLED_SCHEMAS) \ - $(SYS_INSTALLED_DESKTOP_ENTRY) \ - $(SYS_INSTALLED_DBUS_SERVICE) \ - $(SYS_INSTALLED_LAUNCHER_SYMLINK) \ - -SYS_INSTALLED_DIRS := $(sort $(dir $(SYS_INSTALLED_ALL))) - -$(addprefix $(DESTDIR),$(SYS_INSTALLED_DIRS)): - mkdir -p $@ - -installdirs: $(addprefix $(DESTDIR),$(SYS_INSTALLED_DIRS)) - -$(addprefix $(DESTDIR),$(SYS_INSTALLED_CONTENT)): $(DESTDIR)$(SYS_INSTALLED_EXTENSION_DIR)/%: % | installdirs - $(INSTALL) $< $@ - -$(addprefix $(DESTDIR),$(SYS_INSTALLED_SCHEMAS)): $(DESTDIR)$(datadir)/glib-2.0/%: % | installdirs - $(INSTALL) $< $@ - -$(addprefix $(DESTDIR),$(SYS_INSTALLED_CONTENT) $(SYS_INSTALLED_SCHEMAS)): INSTALL := $(INSTALL_DATA) -$(addprefix $(DESTDIR),$(SYS_INSTALLED_EXECUTABLES)): INSTALL := $(INSTALL_PROGRAM) - -$(CONFIGURED_DESKTOP_ENTRY) $(CONFIGURED_DBUS_SERVICE): - sed -e 's:@LAUNCHER@:$(SYS_INSTALLED_LAUNCHER):g' $< >$@ - -$(CONFIGURED_DESKTOP_ENTRY): $(UNCONFIGURED_DESKTOP_ENTRY) -$(CONFIGURED_DBUS_SERVICE): $(UNCONFIGURED_DBUS_SERVICE) - -CLEAN += $(CONFIGURED_DESKTOP_ENTRY) $(CONFIGURED_DBUS_SERVICE) - -DESKTOP_FILE_VALIDATE_TOOL := $(call find-tool,desktop-file-validate) - -desktop-file-validate: $(DESKTOP_FILE_VALIDATE_TOOL) $(CONFIGURED_DESKTOP_ENTRY) - $^ - -.PHONY: desktop-file-validate - -ifneq (tool-not-found/desktop-file-validate,$(DESKTOP_FILE_VALIDATE_TOOL)) -all: desktop-file-validate -endif - -$(addprefix $(DESTDIR),$(SYS_INSTALLED_DESKTOP_ENTRY) $(SYS_INSTALLED_DBUS_SERVICE)): | installdirs - $(INSTALL_DATA) $< $@ - -$(addprefix $(DESTDIR),$(SYS_INSTALLED_DESKTOP_ENTRY)): $(CONFIGURED_DESKTOP_ENTRY) -$(addprefix $(DESTDIR),$(SYS_INSTALLED_DBUS_SERVICE)): $(CONFIGURED_DBUS_SERVICE) - -$(addprefix $(DESTDIR),$(SYS_INSTALLED_LAUNCHER_SYMLINK)): | installdirs - ln -s $(SYS_INSTALLED_LAUNCHER) $@ - -system-schemas-compile system-schemas-compile-nodeps: $(GLIB_COMPILE_SCHEMAS) - $(GLIB_COMPILE_SCHEMAS) $(DESTDIR)$(datadir)/glib-2.0/schemas - -system-schemas-compile: $(addprefix $(DESTDIR),$(SYS_INSTALLED_SCHEMAS)) - -.PHONY: system-schemas-compile system-schemas-compile-nodeps - -system-install: $(addprefix $(DESTDIR),$(SYS_INSTALLED_ALL)) - -system-uninstall: - $(RM) $(addprefix $(DESTDIR),$(SYS_INSTALLED_ALL)) - $(RM) -r $(DESTDIR)$(SYS_INSTALLED_EXTENSION_DIR) - -.PHONY: system-install system-uninstall installdirs - -ifeq ($(DESTDIR),) -system-install: system-schemas-compile -system-uninstall: system-schemas-compile-nodeps -endif - -# System/user install autodetect - -ifneq ($(DESTDIR),) -INSTALL_FLAVOR := system -else ifeq ($(shell id -u),0) -INSTALL_FLAVOR := system -else -INSTALL_FLAVOR := user -endif - -install: $(INSTALL_FLAVOR)-install -uninstall: $(INSTALL_FLAVOR)-uninstall - -.PHONY: install uninstall - -# develop/symlink install - -DEVELOP_SYMLINK := $(HOME)/.local/share/gnome-shell/extensions/$(EXTENSION_UUID) - -develop: build - mkdir -p "$(dir $(DEVELOP_SYMLINK))" - @if [[ -e "$(DEVELOP_SYMLINK)" && ! -L "$(DEVELOP_SYMLINK)" ]]; then \ - echo "$(DEVELOP_SYMLINK) exists and is not a symlink, not overwriting"; exit 1; \ - fi - if [[ "$(abspath .)" != "$(abspath $(DEVELOP_SYMLINK))" ]]; then \ - ln -snf "$(abspath .)" "$(DEVELOP_SYMLINK)"; \ - fi - -develop-uninstall: - if [[ -L "$(DEVELOP_SYMLINK)" ]]; then \ - unlink "$(DEVELOP_SYMLINK)"; \ - fi - -.PHONY: develop develop-uninstall - -# clean - -clean: - $(RM) $(CLEAN) - -.PHONY: clean - -# .ui validation - -GTK3_VALIDATE_UI := $(addprefix gtk-builder-validate/,$(GTK3_UI)) - -$(GTK3_VALIDATE_UI): gtk-builder-validate/%: % $(GTK_BUILDER_TOOL) - $(GTK_BUILDER_TOOL) validate $< - -.PHONY: $(GTK3_VALIDATE_UI) - -GTK4_VALIDATE_UI := $(addprefix gtk-builder-validate/,$(GTK4_UI)) - -$(GTK4_VALIDATE_UI): gtk-builder-validate/%: % $(GTK4_BUILDER_TOOL) - $(GTK4_BUILDER_TOOL) validate $< - -.PHONY: $(GTK4_VALIDATE_UI) - -gtk-builder-validate: $(GTK3_VALIDATE_UI) $(GTK4_VALIDATE_UI) - -all: gtk-builder-validate -.PHONY: gtk-builder-validate - -# Translation helpers - -POT_FILE := po/$(EXTENSION_UUID).pot -XGETTEXT := $(call find-tool,xgettext) - -$(POT_FILE): $(TRANSLATABLE_SOURCES) $(XGETTEXT) - $(XGETTEXT) \ - --from-code=UTF-8 \ - --default-domain=$(EXTENSION_UUID) \ - --package-name=ddterm \ - --add-comments \ - --output=$@ \ - $(sort $(TRANSLATABLE_SOURCES)) - -pot: $(POT_FILE) -.PHONY: pot - -MSGCMP_GOALS := $(addprefix msgcmp/, $(LOCALES)) -MSGCMP_FLAGS := --use-untranslated --use-fuzzy -MSGCMP := $(call find-tool,msgcmp) - -$(MSGCMP_GOALS): msgcmp/%: $(LOCALE_SOURCE_PATTERN) $(POT_FILE) $(MSGCMP) - $(MSGCMP) $(MSGCMP_FLAGS) $< $(POT_FILE) - -msgcmp: $(MSGCMP_GOALS) - -msgcmp-strict: override MSGCMP_FLAGS := -msgcmp-strict: $(MSGCMP_GOALS) - -.PHONY: msgcmp msgcmp-strict $(MSGCMP_GOALS) - -MSGMERGE_GOALS := $(addprefix msgmerge/, $(LOCALES)) -MSGMERGE_FLAGS := --no-fuzzy-matching --update -MSGMERGE := $(call find-tool,msgmerge) - -$(MSGMERGE_GOALS): msgmerge/%: $(LOCALE_SOURCE_PATTERN) $(POT_FILE) $(MSGMERGE) - $(MSGMERGE) $(MSGMERGE_FLAGS) $< $(POT_FILE) - -msgmerge: $(MSGMERGE_GOALS) - -msgmerge-fuzzy: override MSGMERGE_FLAGS := --update --previous -msgmerge-fuzzy: $(MSGMERGE_GOALS) - -.PHONY: msgmerge $(MSGMERGE_GOALS) - -# ESLint - -ESLINT_CMD := node_modules/.bin/eslint -ESLINT_OPTS := -NPM_INSTALLED += $(ESLINT_CMD) - -lint/eslintrc-gjs.yml: - curl -o $@ 'https://gitlab.gnome.org/GNOME/gnome-shell/-/raw/39ed7f83fd97a5a3f688d77adb73e00fd24b7bfe/lint/eslintrc-gjs.yml' - -lint: $(ESLINT_CMD) lint/eslintrc-gjs.yml - $< $(ESLINT_OPTS) . - -.PHONY: lint -all: lint - -# Automagic 'npm install' - -NPM_INSTALL := yes - -ifeq ($(call is-true,$(NPM_INSTALL)),1) - -$(NPM_INSTALLED): node_modules/.package-lock.json -NPM := $(call find-tool,npm) - -node_modules/.package-lock.json: package.json package-lock.json $(NPM) - $(NPM) install - -npm: node_modules/.package-lock.json -.PHONY: npm - -endif - -# Various helpers - -prefs enable disable reset info show: - gnome-extensions $@ $(EXTENSION_UUID) - -.PHONY: prefs enable disable reset info show - -toggle quit begin-subscription-leak-check end-subscription-leak-check: - gapplication action com.github.amezin.ddterm $@ - -.PHONY: toggle quit begin-subscription-leak-check end-subscription-leak-check diff --git a/PKGBUILD b/PKGBUILD index 7a9a71350..2ce498e12 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -8,7 +8,7 @@ license=('GPL3') conflicts=('gnome-shell-extension-ddterm') provides=('gnome-shell-extension-ddterm') depends=('gjs' 'gtk3' 'vte3') -makedepends=('git' 'gtk4' 'libxslt') +makedepends=('meson' 'git' 'gtk4' 'libxslt') source=("$pkgname::git+file://$(git rev-parse --show-toplevel)") md5sums=('SKIP') @@ -18,11 +18,10 @@ pkgver() { } build() { - cd "$pkgname" - make build + arch-meson $pkgname build + meson compile -C build } package() { - cd "$pkgname" - make DESTDIR="$pkgdir/" install + meson install -C build --destdir "$pkgdir" } diff --git a/bin/com.github.amezin.ddterm b/bin/com.github.amezin.ddterm.in similarity index 78% rename from bin/com.github.amezin.ddterm rename to bin/com.github.amezin.ddterm.in index 1d078776d..bdbda2f3e 100755 --- a/bin/com.github.amezin.ddterm +++ b/bin/com.github.amezin.ddterm.in @@ -10,4 +10,4 @@ then PATH="$bindir${PATH:+:${PATH}}" fi -exec gjs -m "${bindir%/*}/ddterm/app/main.js" "$@" +exec "@GJS@" -m "${bindir%/*}/ddterm/app/main.js" "$@" diff --git a/bin/meson.build b/bin/meson.build new file mode 100644 index 000000000..de0360602 --- /dev/null +++ b/bin/meson.build @@ -0,0 +1,16 @@ +pack += configure_file( + input: 'com.github.amezin.ddterm.in', + output: '@BASENAME@', + configuration: gjs_config, + install: true, + install_dir: extension_dir / 'bin', + install_mode: 'rwxr-xr-x' +) + +launcher_installed = extension_dir / 'bin' / 'com.github.amezin.ddterm' + +install_symlink( + 'com.github.amezin.ddterm', + pointing_to: launcher_installed, + install_dir: bindir, +) diff --git a/bump-version.sh b/bump-version.sh index 2804ce5d9..d8a922192 100755 --- a/bump-version.sh +++ b/bump-version.sh @@ -4,14 +4,11 @@ set -ex command -V jq -CURRENT_VERSION=$(jq .version metadata.json.in) +CURRENT_VERSION=$(meson rewrite kwargs info project / 2>&1 | jq -r '.kwargs."project#/".version') NEXT_VERSION=$(( ${CURRENT_VERSION} + 1 )) -git tag v${CURRENT_VERSION} - -jq ".version=${NEXT_VERSION}" metadata.json.in > metadata.json.next -mv -f metadata.json.next metadata.json.in - +meson rewrite kwargs set project / version "${NEXT_VERSION}" sed -i "/^pkgver=/c\pkgver=${NEXT_VERSION}" PKGBUILD +git tag "v${CURRENT_VERSION}" git commit -m "[ci skip] Post-release version bump" metadata.json.in PKGBUILD diff --git a/ddterm/app/icons/meson.build b/ddterm/app/icons/meson.build new file mode 100644 index 000000000..f1163f76b --- /dev/null +++ b/ddterm/app/icons/meson.build @@ -0,0 +1,13 @@ +icon_files = files( + 'quotation-symbolic.svg', + 'regex-symbolic.svg', + 'uppercase-symbolic.svg', +) + +foreach icon_file : icon_files + pack += fs.copyfile( + icon_file, + install: true, + install_dir: extension_dir / 'ddterm' / 'app' / 'icons', + ) +endforeach diff --git a/ddterm/app/meson.build b/ddterm/app/meson.build new file mode 100644 index 000000000..59e2b2f66 --- /dev/null +++ b/ddterm/app/meson.build @@ -0,0 +1,49 @@ +app_js_files = files( + 'accellabel.js', + 'application.js', + 'appwindow.js', + 'dependencies.js', + 'extensiondbus.js', + 'gtktheme.js', + 'heapdump.js', + 'init.js', + 'main.js', + 'meta.js', + 'notebook.js', + 'pcre2.js', + 'prefsdialog.js', + 'resources.js', + 'search.js', + 'settings.js', + 'tablabel.js', + 'tcgetpgrp.js', + 'terminal.js', + 'terminalpage.js', + 'terminalsettings.js', + 'urldetect.js', + 'urldetect_patterns.js', + 'waitstatus.js' +) + +app_ui_files = files( + 'menus.ui', +) + +foreach app_file : app_js_files + app_ui_files + files('dependencies.json', 'style.css') + pack += fs.copyfile( + app_file, + install: true, + install_dir: extension_dir / 'ddterm' / 'app', + ) +endforeach + +subdir('icons') + +foreach app_ui_file : app_ui_files + test( + fs.parent(app_ui_file) / fs.name(app_ui_file), + gtk3_builder_tool, + args: ['validate', app_ui_file], + suite: ['gtk-builder-validate'] + ) +endforeach diff --git a/ddterm/meson.build b/ddterm/meson.build new file mode 100644 index 000000000..693d7c1d6 --- /dev/null +++ b/ddterm/meson.build @@ -0,0 +1,62 @@ +ddterm_files = files( + 'com.github.amezin.ddterm.Extension.xml', + 'com.github.amezin.ddterm.HeapDump.xml', + 'com.github.amezin.ddterm.service.in', +) + +foreach ddterm_file : ddterm_files + pack += fs.copyfile( + ddterm_file, + install: true, + install_dir: extension_dir / 'ddterm', + ) +endforeach + +desktop_entry_untranslated = files('com.github.amezin.ddterm.desktop.in.in') + +pack += i18n.merge_file( + input: desktop_entry_untranslated, + output: '@BASENAME@', + po_dir: '../locale', + type: 'desktop', + install: true, + install_dir: extension_dir / 'ddterm', +) + +launcher_config = configuration_data() +launcher_config.set('LAUNCHER', launcher_installed) + +desktop_entry_final = i18n.merge_file( + input: configure_file( + input: desktop_entry_untranslated, + output: '@BASENAME@_configured', + configuration: launcher_config, + ), + output: '@BASENAME@', + po_dir: '../locale', + type: 'desktop', + install: true, + install_dir: applications_dir, +) + +configure_file( + input: 'com.github.amezin.ddterm.service.in', + output: '@BASENAME@', + configuration: launcher_config, + install: true, + install_dir: dbus_service_dir, +) + +subdir('app') +subdir('pref') +subdir('shell') +subdir('util') + +desktop_file_validate_tool = find_program('desktop-file-validate') + +test( + desktop_entry_final.full_path(), + desktop_file_validate_tool, + args: [desktop_entry_final], + suite: ['desktop-file-validate'] +) diff --git a/ddterm/pref/meson.build b/ddterm/pref/meson.build new file mode 100644 index 000000000..21175929d --- /dev/null +++ b/ddterm/pref/meson.build @@ -0,0 +1,31 @@ +pref_files = files( + 'adw.js', + 'animation.js', + 'behavior.js', + 'colors.js', + 'command.js', + 'compatibility.js', + 'panelicon.js', + 'positionsize.js', + 'scrolling.js', + 'shortcuts.js', + 'tabs.js', + 'text.js', + 'util.js', + 'widget.js', +) + +pref_copy_files = [] + +foreach pref_file : pref_files + pref_copy_files += fs.copyfile( + pref_file, + install: true, + install_dir: extension_dir / 'ddterm' / 'pref', + ) +endforeach + +pack += pref_copy_files + +subdir('ui') +subdir('test') diff --git a/ddterm/pref/test/meson.build b/ddterm/pref/test/meson.build new file mode 100644 index 000000000..c3b22d240 --- /dev/null +++ b/ddterm/pref/test/meson.build @@ -0,0 +1,18 @@ +pref_test_common_files = [ + fs.copyfile('common.js'), + pref_copy_files, + schema_copy, + schemas_compiled, +] + +run_target( + 'pref-gtk3-test', + command: [gjs, '-m', fs.copyfile('gtk3.js')], + depends: [pref_test_common_files, pref_ui_gtk3_files] +) + +run_target( + 'pref-gtk4-test', + command: [gjs, '-m', fs.copyfile('gtk4.js')], + depends: [pref_test_common_files, pref_ui_gtk4_files] +) diff --git a/ddterm/pref/ui/gtk3/meson.build b/ddterm/pref/ui/gtk3/meson.build new file mode 100644 index 000000000..2b88d605c --- /dev/null +++ b/ddterm/pref/ui/gtk3/meson.build @@ -0,0 +1,22 @@ +pref_ui_gtk3_files = [] + +foreach pref_ui_file: pref_ui_files + out_file = custom_target( + command: [output_capture, gtk3_builder_tool, 'simplify', '@INPUT@'], + input: pref_ui_file, + output: '@PLAINNAME@', + install: true, + install_dir: extension_dir / 'ddterm' / 'pref' / 'ui' / 'gtk3', + ) + + test( + out_file.full_path(), + gtk3_builder_tool, + args: ['validate', out_file], + suite: ['gtk-builder-validate'] + ) + + pref_ui_gtk3_files += out_file +endforeach + +pack += pref_ui_gtk3_files diff --git a/ddterm/pref/glade/3to4-fixup.xsl b/ddterm/pref/ui/gtk4/3to4-fixup.xsl similarity index 100% rename from ddterm/pref/glade/3to4-fixup.xsl rename to ddterm/pref/ui/gtk4/3to4-fixup.xsl diff --git a/ddterm/pref/ui/gtk4/meson.build b/ddterm/pref/ui/gtk4/meson.build new file mode 100644 index 000000000..1543f22c2 --- /dev/null +++ b/ddterm/pref/ui/gtk4/meson.build @@ -0,0 +1,31 @@ +gtk4_builder_tool = find_program('gtk4-builder-tool') +xsltproc = find_program('xsltproc') + +pref_ui_gtk4_files = [] + +foreach pref_ui_file: pref_ui_files + fixup = custom_target( + command: [xsltproc, '-o', '@OUTPUT@', files('3to4-fixup.xsl'), '@INPUT@'], + input: pref_ui_file, + output: fs.stem(pref_ui_file) + '.fixup.ui', + ) + + out_file = custom_target( + command: [output_capture, gtk4_builder_tool, 'simplify', '--3to4', '@INPUT@'], + input: fixup, + output: fs.name(pref_ui_file), + install: true, + install_dir: extension_dir / 'ddterm' / 'pref' / 'ui' / 'gtk4', + ) + + pref_ui_gtk4_files += out_file + + test( + out_file.full_path(), + gtk4_builder_tool, + args: ['validate', out_file], + suite: ['gtk-builder-validate'] + ) +endforeach + +pack += pref_ui_gtk4_files diff --git a/ddterm/pref/ui/meson.build b/ddterm/pref/ui/meson.build new file mode 100644 index 000000000..209fa0344 --- /dev/null +++ b/ddterm/pref/ui/meson.build @@ -0,0 +1,25 @@ +pref_ui_files = files( + 'prefs-animation.ui', + 'prefs-behavior.ui', + 'prefs-colors.ui', + 'prefs-command.ui', + 'prefs-compatibility.ui', + 'prefs-panel-icon.ui', + 'prefs-position-size.ui', + 'prefs-scrolling.ui', + 'prefs-shortcuts.ui', + 'prefs-tabs.ui', + 'prefs-text.ui', +) + +foreach pref_ui_file: pref_ui_files + test( + fs.parent(pref_ui_file) / fs.name(pref_ui_file), + gtk3_builder_tool, + args: ['validate', pref_ui_file], + suite: ['gtk-builder-validate'] + ) +endforeach + +subdir('gtk3') +subdir('gtk4') diff --git a/ddterm/pref/glade/prefs-animation.ui b/ddterm/pref/ui/prefs-animation.ui similarity index 100% rename from ddterm/pref/glade/prefs-animation.ui rename to ddterm/pref/ui/prefs-animation.ui diff --git a/ddterm/pref/glade/prefs-behavior.ui b/ddterm/pref/ui/prefs-behavior.ui similarity index 100% rename from ddterm/pref/glade/prefs-behavior.ui rename to ddterm/pref/ui/prefs-behavior.ui diff --git a/ddterm/pref/glade/prefs-colors.ui b/ddterm/pref/ui/prefs-colors.ui similarity index 100% rename from ddterm/pref/glade/prefs-colors.ui rename to ddterm/pref/ui/prefs-colors.ui diff --git a/ddterm/pref/glade/prefs-command.ui b/ddterm/pref/ui/prefs-command.ui similarity index 100% rename from ddterm/pref/glade/prefs-command.ui rename to ddterm/pref/ui/prefs-command.ui diff --git a/ddterm/pref/glade/prefs-compatibility.ui b/ddterm/pref/ui/prefs-compatibility.ui similarity index 100% rename from ddterm/pref/glade/prefs-compatibility.ui rename to ddterm/pref/ui/prefs-compatibility.ui diff --git a/ddterm/pref/glade/prefs-panel-icon.ui b/ddterm/pref/ui/prefs-panel-icon.ui similarity index 100% rename from ddterm/pref/glade/prefs-panel-icon.ui rename to ddterm/pref/ui/prefs-panel-icon.ui diff --git a/ddterm/pref/glade/prefs-position-size.ui b/ddterm/pref/ui/prefs-position-size.ui similarity index 100% rename from ddterm/pref/glade/prefs-position-size.ui rename to ddterm/pref/ui/prefs-position-size.ui diff --git a/ddterm/pref/glade/prefs-scrolling.ui b/ddterm/pref/ui/prefs-scrolling.ui similarity index 100% rename from ddterm/pref/glade/prefs-scrolling.ui rename to ddterm/pref/ui/prefs-scrolling.ui diff --git a/ddterm/pref/glade/prefs-shortcuts.ui b/ddterm/pref/ui/prefs-shortcuts.ui similarity index 100% rename from ddterm/pref/glade/prefs-shortcuts.ui rename to ddterm/pref/ui/prefs-shortcuts.ui diff --git a/ddterm/pref/glade/prefs-tabs.ui b/ddterm/pref/ui/prefs-tabs.ui similarity index 100% rename from ddterm/pref/glade/prefs-tabs.ui rename to ddterm/pref/ui/prefs-tabs.ui diff --git a/ddterm/pref/glade/prefs-text.ui b/ddterm/pref/ui/prefs-text.ui similarity index 100% rename from ddterm/pref/glade/prefs-text.ui rename to ddterm/pref/ui/prefs-text.ui diff --git a/ddterm/shell/meson.build b/ddterm/shell/meson.build new file mode 100644 index 000000000..26b0863c3 --- /dev/null +++ b/ddterm/shell/meson.build @@ -0,0 +1,24 @@ +shell_files = files( + 'appcontrol.js', + 'dbusapi.js', + 'extension.js', + 'geometry.js', + 'install.js', + 'notifications.js', + 'packagekit.js', + 'panelicon.js', + 'sd_journal.js', + 'service.js', + 'subprocess.js', + 'windowmatch.js', + 'wlclipboard.js', + 'wm.js', +) + +foreach shell_file : shell_files + pack += fs.copyfile( + shell_file, + install: true, + install_dir: extension_dir / 'ddterm' / 'shell', + ) +endforeach diff --git a/ddterm/util/meson.build b/ddterm/util/meson.build new file mode 100644 index 000000000..a5d133d28 --- /dev/null +++ b/ddterm/util/meson.build @@ -0,0 +1,11 @@ +util_files = files( + 'displayconfig.js', +) + +foreach util_file : util_files + pack += fs.copyfile( + util_file, + install: true, + install_dir: extension_dir / 'ddterm' / 'util', + ) +endforeach diff --git a/docs/Translations.md b/docs/Translations.md index b2d800d6d..af92b0d44 100644 --- a/docs/Translations.md +++ b/docs/Translations.md @@ -11,9 +11,8 @@ a pull request on GitHub. ## Other tools -CI system automatically upates `.pot` and `.po` files using -[`update-pot.sh`](/po/update-pot.sh) script, so there should be no need to run -it manually. +CI system automatically adds new strings to `.pot` and `.po` files, using +`msgmerge` build target. There should be no need to run it manually. You can add/edit a `.po` file with the tool of your choice and create a pull request. diff --git a/locale b/locale new file mode 120000 index 000000000..1664e9e3b --- /dev/null +++ b/locale @@ -0,0 +1 @@ +po \ No newline at end of file diff --git a/meson.build b/meson.build new file mode 100644 index 000000000..ec6b357b8 --- /dev/null +++ b/meson.build @@ -0,0 +1,180 @@ +project( + 'ddterm', + version : '50', + meson_version : '>= 1.0.0', + license : 'GPL3+', + default_options : ['prefix=/usr'] +) + +gjs = find_program('gjs', version: '>=1.78.0') + +fs = import('fs') +i18n = import('i18n') + +uuid = 'ddterm@amezin.github.com' +gettext_domain = uuid +settings_schema = 'com.github.amezin.ddterm' + +prefix = get_option('prefix') +bindir = prefix / get_option('bindir') +datadir = prefix / get_option('datadir') + +extension_dir = datadir / 'gnome-shell' / 'extensions' / uuid +schema_dir = datadir / 'glib-2.0' / 'schemas' +applications_dir = datadir / 'applications' +dbus_service_dir = datadir / 'dbus-1' / 'services' + +pack = [] + +pack += fs.copyfile( + 'extension.js', + install: true, + install_dir: extension_dir +) + +pack += fs.copyfile( + 'prefs.js', + install: true, + install_dir: extension_dir +) + +pack += fs.copyfile('LICENSE') + +metadata = configuration_data() +metadata.set('version', meson.project_version()) +metadata.set_quoted('uuid', uuid) +metadata.set_quoted('gettext_domain', gettext_domain) +metadata.set_quoted('settings_schema', settings_schema) + +pack += configure_file( + input: 'metadata.json.in', + output: '@BASENAME@', + configuration: metadata, + install: true, + install_dir: extension_dir, +) + +output_capture = ['sh', '-c', 'exec >"$0" "$@"', '@OUTPUT@'] +need_git_version = fs.read('revision.txt.in').strip() == '$Format:%H$' + +git = find_program('git', disabler: true, required: need_git_version) + +if need_git_version + pack += custom_target( + command: [ + output_capture, + git, + '-C', + '@CURRENT_SOURCE_DIR@', + '--git-dir', + '.git', + 'rev-parse', + 'HEAD' + ], + output: 'revision.txt', + build_always_stale: true, + install: true, + install_dir: extension_dir, + ) +else + pack += fs.copyfile( + 'revision.txt.in', + 'revision.txt', + install: true, + install_dir: extension_dir, + ) +endif + +gjs_config = configuration_data() +gjs_config.set('GJS', gjs.full_path()) + +gtk3_builder_tool = find_program('gtk-builder-tool') + +subdir('bin') +subdir('schemas') +subdir('ddterm') +subdir('locale') + +pack_target = custom_target( + command: [ + 'tools' / 'makezip.py', '--output', '@OUTPUT@', '--relative-to', '@OUTDIR@', '--', '@INPUT@' + ], + input: pack, + output: f'@uuid@.shell-extension.zip', + build_by_default: true, +) + +alias_target('pack', pack_target) + +extensions_tool = find_program('gnome-extensions', required: false, disabler: true) + +run_target( + 'user-install', + command: [extensions_tool, 'install', '-f', pack_target], +) + +run_target('user-uninstall', command: [extensions_tool, 'uninstall', uuid]) + +foreach target: ['prefs', 'enable', 'disable', 'reset'] + run_target(target, command: [extensions_tool, target, uuid]) +endforeach + +gapplication_tool = find_program( + 'gapplication', + required: false, + disabler: true, +) + +foreach target: ['toggle', 'quit'] + run_target(target, command: [gapplication_tool, 'action', 'com.github.amezin.ddterm', target]) +endforeach + +npm_tool = find_program('npm', required: false, disabler: true) + +if meson.version().version_compare('>=1.3.0') + ignore_dir = fs.relative_to( + meson.current_build_dir(), + meson.current_source_dir(), + ) +else + ignore_dir = run_command( + 'python3', + '-c', + 'import os.path; import sys; print(os.path.relpath(*sys.argv[1:]))', + meson.current_build_dir(), + meson.current_source_dir(), + capture: true, + check: true, + ).stdout().strip() +endif + +eslint_extra_args = ['--ignore-pattern', ignore_dir] + +npm_install = custom_target( + command: [npm_tool, '-C', '@CURRENT_SOURCE_DIR@', 'install'], + output: 'npm-install', + depend_files: files('package.json', 'package-lock.json'), + console: true, + env: {'DDTERM_POST_INSTALL_STAMP': meson.current_build_dir() / 'npm-install'} +) + +run_target( + 'eslint', + command: [npm_tool, '-C', '@CURRENT_SOURCE_DIR@', 'run-script', '--', 'lint'] + eslint_extra_args, + depends: npm_install, +) + +run_target( + 'eslint-fix', + command: [npm_tool, '-C', '@CURRENT_SOURCE_DIR@', 'run-script', '--', 'lint:fix'] + eslint_extra_args, + depends: npm_install, +) + +test( + 'eslint', + npm_tool, + args: ['run-script', '--', 'lint'] + eslint_extra_args, + depends: npm_install, + workdir: meson.current_source_dir(), + suite: ['eslint'], +) diff --git a/metadata.json.in b/metadata.json.in index 9fed1eaa5..e5613f75c 100644 --- a/metadata.json.in +++ b/metadata.json.in @@ -1,12 +1,12 @@ { "name": "ddterm", "description": "Another drop down terminal extension for GNOME Shell. With tabs. Works on Wayland natively", - "uuid": "ddterm@amezin.github.com", - "gettext-domain": "ddterm@amezin.github.com", - "settings-schema": "com.github.amezin.ddterm", + "uuid": @uuid@, + "gettext-domain": @gettext_domain@, + "settings-schema": @settings_schema@, "shell-version": [ "45" ], - "version": 50, + "version": @version@, "url": "https://github.com/ddterm/gnome-shell-extension-ddterm" } diff --git a/package-lock.json b/package-lock.json index ca30551fa..37764d699 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "packages": { "": { "name": "gnome-shell-extension-ddterm", + "hasInstallScript": true, "devDependencies": { "eslint": "8.56.0", "eslint-formatter-checkstyle": "^8.40.0", diff --git a/package.json b/package.json index d9a7253f8..8dc5d8e2e 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ }, "scripts": { "lint": "eslint .", - "lint:fix": "eslint --fix ." + "lint:fix": "eslint --fix .", + "postinstall": "if [ -n \"$DDTERM_POST_INSTALL_STAMP\" ]; then touch \"$DDTERM_POST_INSTALL_STAMP\"; fi" } } diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 000000000..0ef2349be --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,35 @@ +ddterm/app/application.js +ddterm/app/appwindow.js +ddterm/app/dependencies.js +ddterm/app/menus.ui +ddterm/app/notebook.js +ddterm/app/prefsdialog.js +ddterm/app/search.js +ddterm/app/tablabel.js +ddterm/app/terminalpage.js +ddterm/com.github.amezin.ddterm.desktop.in.in +ddterm/pref/adw.js +ddterm/pref/animation.js +ddterm/pref/behavior.js +ddterm/pref/colors.js +ddterm/pref/command.js +ddterm/pref/compatibility.js +ddterm/pref/ui/prefs-animation.ui +ddterm/pref/ui/prefs-behavior.ui +ddterm/pref/ui/prefs-colors.ui +ddterm/pref/ui/prefs-command.ui +ddterm/pref/ui/prefs-compatibility.ui +ddterm/pref/ui/prefs-panel-icon.ui +ddterm/pref/ui/prefs-position-size.ui +ddterm/pref/ui/prefs-scrolling.ui +ddterm/pref/ui/prefs-shortcuts.ui +ddterm/pref/ui/prefs-tabs.ui +ddterm/pref/ui/prefs-text.ui +ddterm/pref/panelicon.js +ddterm/pref/positionsize.js +ddterm/pref/scrolling.js +ddterm/pref/shortcuts.js +ddterm/pref/tabs.js +ddterm/pref/text.js +ddterm/shell/notifications.js +ddterm/shell/panelicon.js diff --git a/po/gen-potfiles.py b/po/gen-potfiles.py new file mode 100755 index 000000000..6e4ae5c52 --- /dev/null +++ b/po/gen-potfiles.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +import os.path +import subprocess + + +PATTERNS = [ + ':/**/*.js', + ':/**/*.ui', + ':/**/*.desktop.in', + ':/**/*.desktop.in.in', + # exclude, just in case + ':!/test/', + ':!/tools/', +] + + +def check_file_translatable(filename, xgettext='xgettext', xgettext_args=('--from-code=UTF-8',)): + argv = [xgettext, *xgettext_args, '-o-', filename] + return subprocess.check_output(argv).strip() != b'' + + +def all_git_files(git='git', chdir=os.curdir): + argv = [git, '-C', chdir, 'ls-files', '-z', '--deduplicate', '--full-name', '--'] + PATTERNS + + return [ + os.fsdecode(filename) + for filename in subprocess.check_output(argv).split(b'\0') + if filename + ] + + +def get_toplevel(git='git', chdir=os.curdir): + argv = [git, '-C', chdir, 'rev-parse', '--show-toplevel'] + return os.fsdecode(subprocess.check_output(argv).rstrip(b'\n')) + + +def gen(output, git='git', xgettext='xgettext', chdir=os.curdir, xgettext_args=('--from-code=UTF-8',)): + toplevel = get_toplevel(git=git, chdir=chdir) + + content = sorted( + filename + for filename in all_git_files(git=git, chdir=chdir) + if check_file_translatable(os.path.join(toplevel, filename), xgettext=xgettext, xgettext_args=xgettext_args) + ) + + print(f'# This file is generated by {os.path.basename(__file__)}, do not edit', file=output) + + for line in content: + print(line, file=output) + + +def cli(): + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('-o', '--output', type=argparse.FileType('w')) + parser.add_argument('--git', default='git') + parser.add_argument('--xgettext', default='xgettext') + parser.add_argument('-C', dest='chdir', default=os.curdir) + parser.add_argument('xgettext_args', nargs='*', default=('--from-code=UTF-8',)) + + gen(**vars(parser.parse_args())) + + +if __name__ == '__main__': + cli() diff --git a/po/meson.build b/po/meson.build new file mode 100644 index 000000000..6c2321ae7 --- /dev/null +++ b/po/meson.build @@ -0,0 +1,40 @@ +gettext_args = [ + '--from-code=UTF-8', + '--add-comments', + '--check=ellipsis-unicode', + '--check=space-ellipsis', + '--check=bullet-unicode', + # TODO: '--check=quote-unicode', +] + +gettext_targets = i18n.gettext( + gettext_domain, + args: gettext_args, + install: true, + install_dir: extension_dir / 'locale' +) + +alias_target('locales', gettext_targets[0]) +alias_target('pot', gettext_targets[1]) +alias_target('msgmerge', gettext_targets[2]) + +pack += gettext_targets[0] + +xgettext = find_program('xgettext', disabler: true, required: false) + +run_target( + 'potfiles', + command: [ + 'gen-potfiles.py', + '-C', + '@CURRENT_SOURCE_DIR@', + '--git', + git, + '--xgettext', + xgettext, + '-o', + '@CURRENT_SOURCE_DIR@' / 'POTFILES.in', + '--', + gettext_args + ] +) diff --git a/po/remove-potcdate.sin b/po/remove-potcdate.sin deleted file mode 100644 index 2436c49e7..000000000 --- a/po/remove-potcdate.sin +++ /dev/null @@ -1,19 +0,0 @@ -# Sed script that remove the POT-Creation-Date line in the header entry -# from a POT file. -# -# The distinction between the first and the following occurrences of the -# pattern is achieved by looking at the hold space. -/^"POT-Creation-Date: .*"$/{ -x -# Test if the hold space is empty. -s/P/P/ -ta -# Yes it was empty. First occurrence. Remove the line. -g -d -bb -:a -# The hold space was nonempty. Following occurrences. Do nothing. -x -:b -} diff --git a/po/update-pot.sh b/po/update-pot.sh deleted file mode 100755 index 8a4da3514..000000000 --- a/po/update-pot.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -SCRIPT_DIR=$(CDPATH="" cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) -MAKEFILE_DIR="$SCRIPT_DIR/.." - -remove_potcdate() { - sed -f "$SCRIPT_DIR/remove-potcdate.sin" "$@" -} - -set -ex - -# Update .pot file(s), but keep existing POT-Creation-Date if nothing else changed - -for POTFILE in "$SCRIPT_DIR"/*.pot -do - mv "$POTFILE" "$POTFILE~" # backup - make -C "$MAKEFILE_DIR" "$(realpath --relative-to="$MAKEFILE_DIR" "$POTFILE")" - # Compare ignoring POT-Creation-Date - if diff <(remove_potcdate "$POTFILE~") <(remove_potcdate "$POTFILE") - then - mv "$POTFILE~" "$POTFILE" # restore old file if no changes - exit 0 - fi -done - -make -C "$MAKEFILE_DIR" msgmerge-fuzzy diff --git a/schemas/meson.build b/schemas/meson.build new file mode 100644 index 000000000..2f0dfe006 --- /dev/null +++ b/schemas/meson.build @@ -0,0 +1,31 @@ +schema = files(f'@settings_schema@.gschema.xml') + +glib_compile_schemas_tool = find_program('glib-compile-schemas') + +schemas_compiled = custom_target( + command: [ + glib_compile_schemas_tool, + '--strict', + '--targetdir=@OUTDIR@', + '@CURRENT_SOURCE_DIR@' + ], + input: schema, + output: 'gschemas.compiled', +) + +test( + fs.parent(schema) / fs.name(schema), + glib_compile_schemas_tool, + args: ['--strict', '--dry-run', meson.current_source_dir()], + suite: ['glib-compile-schemas'], +) + +schema_copy = fs.copyfile( + schema, + install: true, + install_dir: schema_dir +) + +pack += schema_copy + +meson.add_install_script(glib_compile_schemas_tool, schema_dir, skip_if_destdir: true) diff --git a/tools/makezip.py b/tools/makezip.py new file mode 100644 index 000000000..c1605c967 --- /dev/null +++ b/tools/makezip.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 + +import argparse +import os.path +import zipfile + + +def makezip(output, inputs, relative_to): + with zipfile.ZipFile( + output, + mode='w', + compression=zipfile.ZIP_DEFLATED, + compresslevel=9, + ) as out: + for infile in inputs: + out.write(infile, arcname=os.path.relpath(infile, relative_to)) + + +def cli(*args, **kwargs): + parser = argparse.ArgumentParser() + parser.add_argument('--relative-to', default=os.curdir) + parser.add_argument('--output', required=True) + parser.add_argument('inputs', nargs='+') + + makezip(**vars(parser.parse_args(*args, **kwargs))) + + +if __name__ == '__main__': + cli()