Merge branch 'master' into briefcase-squashed

# Conflicts:
#	.gitignore
This commit is contained in:
Dan Yeaw 2019-03-21 20:42:33 -04:00
commit e917431053
No known key found for this signature in database
GPG Key ID: 77A923EF537B61A4
47 changed files with 1361 additions and 227 deletions

9
.gitignore vendored
View File

@ -20,8 +20,8 @@ pip-wheel-metadata
# Coverage
.coverage
# Tox
.tox
# Editors
.idea
# Flatpak
flatpak/build
@ -34,4 +34,7 @@ macOS/
windows/
android/
linux/
django/
django/
# Windows Install
win-installer/_build_root

7
.readthedocs.yml Normal file
View File

@ -0,0 +1,7 @@
version: 2
formats: all
sphinx:
configuration: docs/conf.py
python:
install:
- requirements: docs/requirements.txt

View File

@ -1,49 +1,131 @@
Feel free to hack Gaphor. Patches are welcome.
# Contributing
Fetching Development Dependencies
=================================
### We :heart: our Contributors!
Gaphor uses pip to manage in easy way its dependencies.
First off, thank you for considering contributing to Gaphor. It's people like
you that make Gaphor such a great modeling tool.
To fetch and install dependencies as non-root user:
In Linux recommend using a virtual environment for installation. Since pyGTK doesn't work well with a virtualenv,
install it outside the virtual environment and then start your the virtualenv using the --system-site-packages option:
$ virtualenv --system-site-packages venv
$ source venv/bin/activate
$ pip install gaphor
### Why a Guideline?
Running Tests
=============
To run tests on Unix machine
Following these guidelines helps to communicate that you respect the time of
the developers managing and developing this open source project. In return,
they should reciprocate that respect in addressing your issue, assessing
changes, and helping you finalize your pull requests.
Xvfb :2.0 &
DISPLAY=:2.0 nosetests gaphor/ 2>&1 | tee tests.log
### What we are Looking For
Gaphor is an open source project and we love to receive contributions from our
community — you! There are many ways to contribute, from writing tutorials or
blog posts, improving the documentation, submitting bug reports and feature
requests or writing code which can be incorporated into Gaphor itself.
### What we are not Looking For
Please, don't use the issue tracker for support questions. Check whether the
your question can be answered on the
[Gaphor Gitter Channel](https://gitter.im/gaphor/Lobby).
# Ground Rules
### Responsibilities
* Ensure cross-platform compatibility for every change that's accepted.
Windows, Mac, Debian & Ubuntu Linux.
* Ensure that code that goes into core meets all requirements in this
[PR Review Checklist](https://gist.github.com/audreyr/4feef90445b9680475f2).
* Create issues for any major changes and enhancements that you wish to make.
* Discuss things transparently and get community feedback.
* Don't add any classes to the codebase unless absolutely needed. Err on the side of using
functions.
* Keep feature versions as small as possible, preferably one new feature per
version.
* Be welcoming to newcomers and encourage diverse new contributors from all
backgrounds. See the
[Python Community Code of Conduct](https://www.python.org/psf/codeofconduct/).
# Your First Contribution
Unsure where to begin contributing to Gaphor? You can start by looking through
these `first-timers-only` and `up-for-grabs` issues:
* [First-timers-only issues](https://github.com/gaphor/gaphor/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3Afirst-timers-only) -
issues which should only require a few lines of code, and a test or two.
* [Up-for-grabs issues](https://github.com/gaphor/gaphor/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3Aup-for-grabs) -
issues which should be a bit more involved than `first-timers-only` issues.
### Is This Your First Open Source Contribution?
Working on your first Pull Request? You can learn how from this *free* series,
[How to Contribute to an Open Source Project on
GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
At this point, you're ready to make your changes! Feel free to ask for help;
everyone is a beginner at first :smile_cat:
If a maintainer asks you to "rebase" your PR, they're saying that a lot of code
has changed, and that you need to update your branch so it's easier to merge.
# Getting Started
For something that is bigger than a one or two line fix:
1. Create your own fork of the code
2. Install all development dependencies using:
`$ poetry install`
`$ pre-commit install`
If you haven't used poetry before, just run `pip install poetry`, and then run the commands above, it will do the correct thing.
3. Add tests for your changes, run the tests with `pytest`.
4. Do the changes in your fork.
5. If you like the change and think the project could use it:
* Be sure you have the pre-commit hook installed above, it will ensure that
[Black](https://github.com/ambv/black) is automatically run on any changes for
consistent code formatting.
* [Sign](https://help.github.com/articles/signing-commits/) your commits.
* Note the Gaphor Code of Conduct.
* Create a pull request.
Structure
=========
Small contributions such as fixing spelling errors, where the content is small
enough to not be considered intellectual property, can be submitted by a
contributor as a patch, without signing your commit.
Gaphor contains the following modules:
As a rule of thumb, changes are obvious fixes if they do not introduce any new
functionality or creative thinking. As long as the change does not affect
functionality, some likely examples include the following:
* Spelling / grammar fixes
* Typo correction, white space and formatting changes
* Comment clean up
* Bug fixes that change default return values or error codes stored in constants
* Adding logging messages or debugging output
* Changes to metadata files like pyproject.toml, .gitignore, build scripts, etc.
* Moving source files from one directory or package to another
UML
---
The UML module contains the UML 2.0 data model. This part is
quite stable and it is unlikely that code has to be changed
here.
# How to Report a Bug
If you find a security vulnerability, do NOT open an issue. Email dan@yeaw.me instead.
NOTE: The code is generated from a Gaphor model: uml2.gaphor. This
file can be loaded in gaphor.
When filing an issue, make sure to answer the questions in the issue template.
diagram
-------
The diagram module contains items that can be placed in diagrams.
In most cases the classes NamedItem and Relationship can serve
as bases for your class.
1. What version are you using?
2. What operating system are you using?
3. What did you do?
4. What did you expect to see?
5. What did you see instead?
ui
--
The user interface. This is where most of the work is to be done.
# How to Suggest a Feature or Enhancement
If you find yourself wishing for a feature that doesn't exist in Gaphor,
you are probably not alone. There are bound to be others out there with similar
needs. Many of the features that Gaphor has today have been added
because our users saw the need. Open an issue on our issues list on GitHub
which describes the feature you would like to see, why you need it, and how it
should work.
# Code review process
The core team looks at Pull Requests on a regular basis, you should expect a
response within a week. After feedback has been given we expect responses
within two weeks. After two weeks we may close the pull request if it isn't
showing any activity.
# Community
You can chat with the Gaphor community on gitter: https://gitter.im/Gaphor/Lobby.
misc
----
Some utility stuff, such as Actions and aspects are put in here.

View File

@ -2,7 +2,7 @@
[![Build state](https://travis-ci.com/gaphor/gaphor.svg?branch=master)](https://travis-ci.com/gaphor/gaphor)
![Docs build state](https://readthedocs.org/projects/gaphor/badge/?version=latest)
[![Coverage](https://coveralls.io/repos/github/gaphor/gaphor/badge.svg?branch=master)](https://coveralls.io/github/gaphor/gaphor?branch=master)
[![Coverage Status](https://coveralls.io/repos/github/gaphor/gaphor/badge.svg?branch=master)](https://coveralls.io/github/gaphor/gaphor?branch=master)
[![PyPI](https://img.shields.io/pypi/v/gaphor.svg)](https://pypi.org/project/gaphor)
[![Downloads](https://pepy.tech/badge/gaphor)](https://pepy.tech/project/gaphor)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)

View File

@ -1,5 +1,6 @@
# Makefile for Sphinx documentation
#
Python ?= python3
# You can set these variables from the command line.
SPHINXOPTS =

View File

@ -1,222 +1,187 @@
# -*- coding: utf-8 -*-
#
# This file is execfile()d with the current directory set to its containing dir.
# Configuration file for the Sphinx documentation builder.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# This file does only contain a selection of the most common options. For a
# full list see the documentation:
# http://www.sphinx-doc.org/en/master/config
import sys, os
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
from pathlib import Path
# -- General configuration -----------------------------------------------------
from tomlkit import parse
# -- Project information -----------------------------------------------------
project = "Gaphor"
copyright = "2019, Arjan J. Molenaar"
author = "Arjan J. Molenaar"
# The short X.Y version
version = ""
project_dir = Path(__file__).resolve().parent.parent
f = project_dir.joinpath("pyproject.toml")
release = parse(f.read_text())["tool"]["poetry"]["version"]
# -- General configuration ---------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.doctest",
"sphinx.ext.todo",
"sphinx.ext.intersphinx",
"sphinx.ext.coverage",
"sphinx.ext.viewcode",
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
# The suffix of source filenames.
source_suffix = ".txt"
# The encoding of source files.
# source_encoding = 'utf-8-sig'
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = ".rst"
# The master toctree document.
master_doc = "contents"
# General information about the project.
project = u"Gaphor"
copyright = u"2012, Gaphor development team"
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = "0.17.1"
# The full version, including alpha/beta/rc tags.
release = "0.17.1"
master_doc = "index"
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
# language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ["_build"]
# The reST default role (used for this markup: `text`) to use for all documents.
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
pygments_style = None
# -- Options for HTML output ---------------------------------------------------
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = "default"
#
html_theme = "sphinx_rtd_theme"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]
# If not '', a 'Last updated on:' timestamp is inserted at the bottom of every page,
# using the given strftime format.
# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself. Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}
# If false, no module index is generated.
# html_domain_indices = True
# If false, no index is generated.
# html_use_index = True
# If true, the index is split into individual pages for each letter.
# html_split_index = False
# If true, links to the reST sources are added to the pages.
# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None
# -- Options for HTMLHelp output ---------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = "Gaphordoc"
# -- Options for LaTeX output --------------------------------------------------
# -- Options for LaTeX output ------------------------------------------------
# The paper size ('letter' or 'a4').
# latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
# latex_font_size = '10pt'
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(
"contents",
"Gaphor.tex",
u"Gaphor Documentation",
u"Gaphor development team",
"manual",
)
(master_doc, "Gaphor.tex", "Gaphor Documentation", "Arjan J. Molenaar", "manual")
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False
# If true, show page references after internal links.
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
# latex_show_urls = False
# Additional stuff for the LaTeX preamble.
# latex_preamble = ''
# Documents to append as an appendix to all manuals.
# latex_appendices = []
# If false, no module index is generated.
# latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# -- Options for manual page output ------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
("contents", "gaphor", u"Gaphor Documentation", [u"Gaphor development team"], 1)
man_pages = [(master_doc, "gaphor", "Gaphor Documentation", [author], 1)]
# -- Options for Texinfo output ----------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(
master_doc,
"Gaphor",
"Gaphor Documentation",
author,
"Gaphor",
"One line description of project.",
"Miscellaneous",
)
]
# -- Options for Epub output -------------------------------------------------
# Bibliographic Dublin Core info.
epub_title = project
# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#
# epub_identifier = ''
# A unique identification for the text.
#
# epub_uid = ''
# A list of files that should not be packed into the epub file.
epub_exclude_files = ["search.html"]
# -- Extension configuration -------------------------------------------------
# -- Options for intersphinx extension ---------------------------------------
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {"https://docs.python.org/": None}

View File

@ -1,17 +1,14 @@
######################
Documentation contents
######################
Welcome to Gaphor's documentation!
==================================
*The source is the documentation.*
Well, not for us.
Currently, there's not a lot of documentation though. For those of you interested in Gaphor there's:
Some highlights of the documentation:
* A :doc:`manual <manual/index>`. It outlines some of the ideas in and behind Gaphor.
* The :ref:`tech-section` contains some interesting articles about the technology that drives Gaphor and Gaphas, Gaphor's canvas widget.
If you're into writing plug-ins for Gaphor you should have a look at our fabulous `Hello world <http://github.com/amolenaar/gaphor.plugins.helloworld>`_ plug-in.
If you're into writing plug-ins for Gaphor you should have a look at our
fabulous `Hello world <http://github.com/amolenaar/gaphor.plugins.helloworld>`_
plug-in.
.. toctree::
:maxdepth: 2
@ -23,8 +20,9 @@ Running Gaphor on different platforms:
.. toctree::
:maxdepth: 1
windows
linux
win32
macos
custominstall
@ -62,5 +60,3 @@ External links
* The `official UML metamodel specification <http://www.omg.org/technology/documents/modeling_spec_catalog.htm#UML>`_. This ''is'' our data model.
..
# vim:syntax=rst

3
docs/macos.rst Normal file
View File

@ -0,0 +1,3 @@
Gaphor on macOS
===============

View File

@ -12,11 +12,11 @@ highly complex models.
Gaphor is designed around the following principles:
- Simplicity
The application should be easy to use. Only some basic knowledge of UML is required.
The application should be easy to use. Only some basic knowledge of UML is required.
- Consistency
UML is a graphical modeling language, so all modeling is done in a diagram [#f1]_ .
UML is a graphical modeling language, so all modeling is done in a diagram [#f1]_ .
- Workability
The application should not bother the user every time they do something non-UML-ish.
The application should not bother the user every time they do something non-UML-ish.
This manual serves as a reference for all Gaphor has to offer. So, you may read it from start to finish, or jump to a section that interests you.

5
docs/requirements.txt Normal file
View File

@ -0,0 +1,5 @@
docutils==0.14
Pygments==2.3.1
sphinx-rtd-theme==0.4.3
sphinxcontrib-websupport==1.1.0
tomlkit==0.5.3

View File

@ -53,5 +53,5 @@ information along with its service definition.
.. seealso::
Writing plugins :ref:`<manual/plugins>`
:doc:`Writing plugins <manual/plugins>`

View File

@ -30,14 +30,14 @@ All elements inside a canvas have a tag ``Item``.
<ref refid="1"/>
</namespace>
<canvas extents="(9.0, 9.0, 189.0, 247.0)" grid_bg="0xFFFFFFFF"
grid_color="0x80ff" grid_int_x="10.0" grid_int_y="10.0"
grid_ofs_x="0.0" grid_ofs_y="0.0" snap_to_grid="0"
static_extents="0" affine="(1.0, 0.0, 0.0, 1.0, 0.0, 0.0)"
id="DCE:xxxx">
grid_color="0x80ff" grid_int_x="10.0" grid_int_y="10.0"
grid_ofs_x="0.0" grid_ofs_y="0.0" snap_to_grid="0"
static_extents="0" affine="(1.0, 0.0, 0.0, 1.0, 0.0, 0.0)"
id="DCE:xxxx">
<item affine="(1.0, 0.0, 0.0, 1.0, 150.0, 50.0)" cid="0x8293e74"
height="78.0" subject="3" type="ActorItem" width="38.0"/>
height="78.0" subject="3" type="ActorItem" width="38.0"/>
<item affine="(1.0, 0.0, 0.0, 1.0, 10.0, 10.0)" cid="0x82e7d74"
height="26.0" subject="5" type="CommentItem" width="100.0"/>
height="26.0" subject="5" type="CommentItem" width="100.0"/>
</canvas>
</Diagram>
<Actor id="3">
@ -46,7 +46,7 @@ All elements inside a canvas have a tag ``Item``.
</name>
<namespace>
<ref refid="1"/>
</namespace
</namespace>
</Actor>
<UseCase id="4">
<namespace>

3
docs/windows.rst Normal file
View File

@ -0,0 +1,3 @@
Gaphor on Windows
=================

View File

@ -105,7 +105,7 @@ class Element(object):
def isKindOf(self, class_):
"""
Returns true if the object is an instance of class_.
Returns true if the object is an instance of `class_`.
"""
return isinstance(self, class_)

View File

@ -1,7 +1,4 @@
# vim: sw=4
"""
Factory for and registration of model elements.
"""
"""Factory for and registration of model elements."""
import uuid
from zope import component
@ -27,13 +24,12 @@ class ElementFactory(object):
The ElementFactory is used to create elements and do lookups to
elements.
Notifications are send with as arguments (name, element, *user_data).
Notifications are sent as arguments (name, element, `*user_data`).
The following names are used:
create - a new model element is created (element is newly created element)
remove - a model element is removed (element is to be removed element)
model - a new model has been loaded (element is None)
flush - model is flushed: all element are removed from the factory
(element is None)
model - a new model has been loaded (element is None) flush - model is
flushed: all element are removed from the factory (element is None)
"""
def __init__(self):

View File

@ -1,4 +1,5 @@
[pytest]
testpaths = gaphor tests docs
doctest-extension=.txt
doctest-extension=.rst
python_files = test_*.py
addopts = --doctest-modules

View File

@ -94,6 +94,7 @@ setup(
"PyGObject >= 3.30.0",
"gaphas >= 0.7.2",
"zope.component >= 3.4.0",
"zope.interface >= 4.6.0",
],
zip_safe=False,
entry_points={

45
win-installer/README.md Normal file
View File

@ -0,0 +1,45 @@
# Windows Installer Build Scripts
We use msys2 for creating the Windows installer and development on Windows
because that is what PyGObject currently supports.
## Development
For developing on Windows you have two choices.
#### 1. Use an Existing Gaphor Installation Plus a Git Checkout:
- Clone the git repo with some git client
- Download and install the latest [installer
build](https://github.com/gaphor/gaphor/releases/download/latest/gaphor-latest-installer.exe)
- Go to setup.py in the git checkout and run C:\Program
Files\Gaphor\bin\python.exe setup.py run.
#### 2. Use a Full MSYS2 Environment
- Download msys2 64-bit from https://msys2.org
- Follow instructions on https://msys2.org
- Execute C:\msys64\mingw64.exe
- Run `pacman -Syu` to update packages
- Run `pacman -S git` to install git
- Run git clone https://github.com/gaphor/gaphor.git
- Run cd gaphor/win_installer to end up where this README exists.
- Execute `./bootstrap.sh` to install all the needed dependencies.
- Now go to the source code `cd ../`
- To run Gaphor execute `python3 setup.py run`
## Creating an Installer
Simply run `./build.sh` and both the installer and the portable
installer should appear in this directory.
You can also run the build using a specific git version:
1. Pass a git tag with: `./build.sh release-1.0.0`
1. Pass a git commit hash with: `./build.sh a5d3e53406fadd1fe089aa995b650949256d4981`
1. Pass nothing to build master
Note: `build.sh` clones from the local repository and not from GitHub so any
commits present locally will be cloned as well.
## Updating an Existing Installer
We directly follow msys2 upstream so building the installer two weeks later
might result in newer versions of dependencies being used. To reduce the risk of
stable release breakage you can use an existing installer and just install a
newer Gaphor version into it and then repack it:
`./rebuild.sh gaphor-1.0.0-installer.exe [git tag / commit]`

318
win-installer/_base.sh Normal file
View File

@ -0,0 +1,318 @@
#!/usr/bin/env bash
# Copyright 2016 Christoph Reiter, 2019 Dan Yeaw
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
set -e
DIR="$( cd "$( dirname "$0" )" && pwd )"
cd "${DIR}"
# CONFIG START
ARCH="x86_64"
BUILD_VERSION="0"
# CONFIG END
MISC="${DIR}"/misc
if [ "${ARCH}" = "x86_64" ]; then
MINGW="mingw64"
else
MINGW="mingw32"
fi
VERSION="0.0.0"
VERSION_DESC="UNKNOWN"
function set_build_root {
BUILD_ROOT="$1"
REPO_CLONE="${BUILD_ROOT}"/gaphor
MINGW_ROOT="${BUILD_ROOT}/${MINGW}"
}
set_build_root "${DIR}/_build_root"
function build_pacman {
pacman --cachedir "/var/cache/pacman/pkg" --root "${BUILD_ROOT}" "$@"
}
function build_pip {
"${BUILD_ROOT}"/"${MINGW}"/bin/pip3.exe "$@"
}
function build_python {
"${BUILD_ROOT}"/"${MINGW}"/bin/python3.exe "$@"
}
function build_compileall_pyconly {
MSYSTEM= build_python -m compileall --invalidation-mode unchecked-hash -b "$@"
}
function build_compileall {
MSYSTEM= build_python -m compileall --invalidation-mode unchecked-hash "$@"
}
function install_pre_deps {
pacman -S --needed --noconfirm p7zip git dos2unix \
mingw-w64-"${ARCH}"-nsis mingw-w64-"${ARCH}"-wget mingw-w64-"${ARCH}"-toolchain
}
function create_root {
mkdir -p "${BUILD_ROOT}"
mkdir -p "${BUILD_ROOT}"/var/lib/pacman
mkdir -p "${BUILD_ROOT}"/var/log
mkdir -p "${BUILD_ROOT}"/tmp
build_pacman --noconfirm -Syu
build_pacman --noconfirm -S base
}
function extract_installer {
[ -z "$1" ] && (echo "Missing arg"; exit 1)
mkdir -p "$BUILD_ROOT"
7z x -o"$BUILD_ROOT"/"$MINGW" "$1"
rm -rf "$MINGW_ROOT"/'$PLUGINSDIR' "$MINGW_ROOT"/*.txt "$MINGW_ROOT"/*.nsi
}
function install_deps {
build_pacman --noconfirm -S \
mingw-w64-"${ARCH}"-gtk3 \
mingw-w64-"${ARCH}"-python3 \
mingw-w64-"${ARCH}"-python3-gobject \
mingw-w64-"${ARCH}"-python3-cairo \
mingw-w64-"${ARCH}"-python3-pip \
mingw-w64-"${ARCH}"-python3-setuptools \
mingw-w64-"${ARCH}"-python3-zope.interface
# First time installing pip has post-install errors, reinstall to fix
# sed: can't read mingw64/bin/pip3-script.py: No such file or directory
# sed: can't read mingw64/bin/pip3.7-script.py: No such file or directory
# error: command (/usr/bin/bash /usr/bin/bash -c . /tmp/alpm_omSbWr/.INSTALL; post_install 19.0.1-1 ) failed to execute correctly
build_pacman --noconfirm -S mingw-w64-"${ARCH}"-python3-pip
PIP_REQUIREMENTS="\
pycairo==1.18.0
PyGObject==3.30.4
gaphas==1.0.0
zope.component==4.5
tomlkit==0.5.3
"
build_pip install $(echo "$PIP_REQUIREMENTS" | tr ["\\n"] [" "])
}
function get_version {
python3 - <<END
from tomlkit import parse
with open('../pyproject.toml', 'r') as f:
parsed_toml = parse(f.read())
print(parsed_toml["tool"]["poetry"]["version"])
END
}
function install_gaphor {
[ -z "$1" ] && (echo "Missing arg"; exit 1)
rm -Rf "${REPO_CLONE}"
git clone "${DIR}"/.. "${REPO_CLONE}"
cd "${REPO_CLONE}"
git checkout "$1"
build_python setup.py install
cd "${DIR}"
# Create launchers
python3 "${MISC}"/create-launcher.py \
"${VERSION}" "${MINGW_ROOT}"/bin
VERSION=$(get_version)
VERSION_DESC="$VERSION"
if [ "$1" = "master" ]
then
local GIT_REV=$(git rev-list --count HEAD)
local GIT_HASH=$(git rev-parse --short HEAD)
VERSION_DESC="$VERSION-rev$GIT_REV-$GIT_HASH"
fi
build_compileall -d "" -f -q "$(cygpath -w "${MINGW_ROOT}")"
}
function cleanup_before {
# these all have svg variants
find "${MINGW_ROOT}"/share/icons -name "*.symbolic.png" -exec rm -f {} \;
# remove some larger ones
rm -Rf "${MINGW_ROOT}/share/icons/Adwaita/512x512"
rm -Rf "${MINGW_ROOT}/share/icons/Adwaita/256x256"
rm -Rf "${MINGW_ROOT}/share/icons/Adwaita/96x96"
rm -Rf "${MINGW_ROOT}/share/icons/Adwaita/48x48"
"${MINGW_ROOT}"/bin/gtk-update-icon-cache-3.0.exe \
"${MINGW_ROOT}"/share/icons/Adwaita
# python related, before installing gaphor
rm -Rf "${MINGW_ROOT}"/lib/python3.*/test
rm -f "${MINGW_ROOT}"/lib/python3.*/lib-dynload/_tkinter*
find "${MINGW_ROOT}"/lib/python3.* -type d -name "test*" \
-prune -exec rm -rf {} \;
find "${MINGW_ROOT}"/lib/python3.* -type d -name "*_test*" \
-prune -exec rm -rf {} \;
find "${MINGW_ROOT}"/bin -name "*.pyo" -exec rm -f {} \;
find "${MINGW_ROOT}"/bin -name "*.pyc" -exec rm -f {} \;
build_compileall_pyconly -d "" -f -q "$(cygpath -w "${MINGW_ROOT}")"
find "${MINGW_ROOT}" -name "*.py" -exec rm -f {} \;
find "${MINGW_ROOT}" -type d -name "__pycache__" -prune -exec rm -rf {} \;
}
function cleanup_after {
# delete translations we don't support
for d in "${MINGW_ROOT}"/share/locale/*/LC_MESSAGES; do
if [ ! -f "${d}"/gaphor.mo ]; then
rm -Rf "${d}"
fi
done
find "${MINGW_ROOT}" -regextype "posix-extended" -name "*.exe" -a ! \
-iregex ".*/(gaphor|exfalso|operon|python|gspawn-)[^/]*\\.exe" \
-exec rm -f {} \;
rm -Rf "${MINGW_ROOT}"/libexec
rm -Rf "${MINGW_ROOT}"/share/gtk-doc
rm -Rf "${MINGW_ROOT}"/include
rm -Rf "${MINGW_ROOT}"/var
rm -Rf "${MINGW_ROOT}"/etc/config.site
rm -Rf "${MINGW_ROOT}"/etc/pki
rm -Rf "${MINGW_ROOT}"/etc/pkcs11
rm -Rf "${MINGW_ROOT}"/etc/gtk-3.0/im-multipress.conf
rm -Rf "${MINGW_ROOT}"/share/zsh
rm -Rf "${MINGW_ROOT}"/share/pixmaps
rm -Rf "${MINGW_ROOT}"/share/gnome-shell
rm -Rf "${MINGW_ROOT}"/share/dbus-1
rm -Rf "${MINGW_ROOT}"/share/gir-1.0
rm -Rf "${MINGW_ROOT}"/share/doc
rm -Rf "${MINGW_ROOT}"/share/man
rm -Rf "${MINGW_ROOT}"/share/info
rm -Rf "${MINGW_ROOT}"/share/mime
rm -Rf "${MINGW_ROOT}"/share/gettext
rm -Rf "${MINGW_ROOT}"/share/libtool
rm -Rf "${MINGW_ROOT}"/share/licenses
rm -Rf "${MINGW_ROOT}"/share/appdata
rm -Rf "${MINGW_ROOT}"/share/aclocal
rm -Rf "${MINGW_ROOT}"/share/ffmpeg
rm -Rf "${MINGW_ROOT}"/share/vala
rm -Rf "${MINGW_ROOT}"/share/readline
rm -Rf "${MINGW_ROOT}"/share/xml
rm -Rf "${MINGW_ROOT}"/share/bash-completion
rm -Rf "${MINGW_ROOT}"/share/common-lisp
rm -Rf "${MINGW_ROOT}"/share/emacs
rm -Rf "${MINGW_ROOT}"/share/gdb
rm -Rf "${MINGW_ROOT}"/share/libcaca
rm -Rf "${MINGW_ROOT}"/share/gettext
rm -Rf "${MINGW_ROOT}"/share/gst-plugins-base
rm -Rf "${MINGW_ROOT}"/share/gst-plugins-bad
rm -Rf "${MINGW_ROOT}"/share/libgpg-error
rm -Rf "${MINGW_ROOT}"/share/p11-kit
rm -Rf "${MINGW_ROOT}"/share/pki
rm -Rf "${MINGW_ROOT}"/share/thumbnailers
rm -Rf "${MINGW_ROOT}"/share/gtk-3.0
rm -Rf "${MINGW_ROOT}"/share/nghttp2
rm -Rf "${MINGW_ROOT}"/share/themes
rm -Rf "${MINGW_ROOT}"/share/fontconfig
rm -Rf "${MINGW_ROOT}"/share/gettext-*
rm -Rf "${MINGW_ROOT}"/share/installed-tests
find "${MINGW_ROOT}"/share/glib-2.0 -type f ! \
-name "*.compiled" -exec rm -f {} \;
rm -Rf "${MINGW_ROOT}"/lib/cmake
rm -Rf "${MINGW_ROOT}"/lib/gettext
rm -Rf "${MINGW_ROOT}"/lib/gtk-3.0
rm -Rf "${MINGW_ROOT}"/lib/mpg123
rm -Rf "${MINGW_ROOT}"/lib/p11-kit
rm -Rf "${MINGW_ROOT}"/lib/pkcs11
rm -Rf "${MINGW_ROOT}"/lib/ruby
rm -Rf "${MINGW_ROOT}"/lib/engines
find "${MINGW_ROOT}" -name "*.a" -exec rm -f {} \;
find "${MINGW_ROOT}" -name "*.whl" -exec rm -f {} \;
find "${MINGW_ROOT}" -name "*.h" -exec rm -f {} \;
find "${MINGW_ROOT}" -name "*.la" -exec rm -f {} \;
find "${MINGW_ROOT}" -name "*.sh" -exec rm -f {} \;
find "${MINGW_ROOT}" -name "*.jar" -exec rm -f {} \;
find "${MINGW_ROOT}" -name "*.def" -exec rm -f {} \;
find "${MINGW_ROOT}" -name "*.cmd" -exec rm -f {} \;
find "${MINGW_ROOT}" -name "*.cmake" -exec rm -f {} \;
find "${MINGW_ROOT}" -name "*.pc" -exec rm -f {} \;
find "${MINGW_ROOT}" -name "*.desktop" -exec rm -f {} \;
find "${MINGW_ROOT}" -name "*.manifest" -exec rm -f {} \;
find "${MINGW_ROOT}" -name "*.pyo" -exec rm -f {} \;
find "${MINGW_ROOT}"/bin -name "*-config" -exec rm -f {} \;
find "${MINGW_ROOT}"/bin -name "easy_install*" -exec rm -f {} \;
find "${MINGW_ROOT}" -regex ".*/bin/[^.]+" -exec rm -f {} \;
find "${MINGW_ROOT}" -regex ".*/bin/[^.]+\\.[0-9]+" -exec rm -f {} \;
find "${MINGW_ROOT}" -name "gtk30-properties.mo" -exec rm -rf {} \;
find "${MINGW_ROOT}" -name "gettext-tools.mo" -exec rm -rf {} \;
find "${MINGW_ROOT}" -name "libexif-12.mo" -exec rm -rf {} \;
find "${MINGW_ROOT}" -name "xz.mo" -exec rm -rf {} \;
find "${MINGW_ROOT}" -name "libgpg-error.mo" -exec rm -rf {} \;
find "${MINGW_ROOT}" -name "old_root.pem" -exec rm -rf {} \;
find "${MINGW_ROOT}" -name "weak.pem" -exec rm -rf {} \;
find "${MINGW_ROOT}"/bin -name "*.pyo" -exec rm -f {} \;
find "${MINGW_ROOT}"/bin -name "*.pyc" -exec rm -f {} \;
build_python "${MISC}/depcheck.py" --delete
find "${MINGW_ROOT}" -type d -empty -delete
}
function build_installer {
BUILDPY=$(echo "${MINGW_ROOT}"/lib/python3.*/site-packages/gaphor*egg/gaphor)/build.py
cp "${REPO_CLONE}"/win-installer/build.py "$BUILDPY"
echo 'BUILD_TYPE = u"windows"' >> "$BUILDPY"
echo "BUILD_VERSION = $BUILD_VERSION" >> "$BUILDPY"
(cd "$REPO_CLONE" && echo "BUILD_INFO = u\"$(git rev-parse --short HEAD)\"" >> "$BUILDPY")
build_compileall -d "" -q -f "$BUILDPY"
cp misc/gaphor.ico "${BUILD_ROOT}"
(cd "${MINGW_ROOT}" && makensis -NOCD -DVERSION="$VERSION_DESC" "${MISC}"/win_installer.nsi)
mv "${MINGW_ROOT}/gaphor-LATEST.exe" "$DIR/gaphor-$VERSION_DESC-installer.exe"
}
function build_portable_installer {
cp "${REPO_CLONE}"/win-installer/build.py "$BUILDPY"
echo 'BUILD_TYPE = u"windows-portable"' >> "$BUILDPY"
echo "BUILD_VERSION = $BUILD_VERSION" >> "$BUILDPY"
(cd "$REPO_CLONE" && echo "BUILD_INFO = u\"$(git rev-parse --short HEAD)\"" >> "$BUILDPY")
build_compileall -d "" -q -f "$BUILDPY"
local PORTABLE="$DIR/gaphor-$VERSION_DESC-portable"
rm -rf "$PORTABLE"
mkdir "$PORTABLE"
cp "$MISC"/gaphor.lnk "$PORTABLE"
cp "$MISC"/README-PORTABLE.txt "$PORTABLE"/README.txt
unix2dos "$PORTABLE"/README.txt
mkdir "$PORTABLE"/config
cp -RT "${MINGW_ROOT}" "$PORTABLE"/data
rm -Rf 7zout 7z1900-x64.exe
7z a payload.7z "$PORTABLE"
wget.exe -P "$DIR" -c https://www.7-zip.org/a/7z1900-x64.exe
7z x -o7zout 7z1900-x64.exe
cat 7zout/7z.sfx payload.7z > "$PORTABLE".exe
rm -Rf 7zout 7z1900-x64.exe payload.7z "$PORTABLE"
}

View File

@ -0,0 +1,21 @@
import subprocess
# Update pacman packages
subprocess.run("pacman -Suy")
# Install PyGObject Development Environment
subprocess.run(
"pacman -S --needed --noconfirm"
"base-devel"
"mingw-w64-x68_64-toolchain"
"git"
"mingw-w64-x68_64-python3"
"mingw-w64-x68_64-python3-cairo"
"mingw-w64-x68_64-gobject-gobject"
"mingw-w64-x68_64-python3-pip"
"mingw-w64-x68_64-setuptools"
)
# Install Gaphor dependencies
subprocess.run("pip3 install --user -U" "gaphas" "zope.component" "pycairo" "PyGObject")

17
win-installer/build.py Normal file
View File

@ -0,0 +1,17 @@
# Copyright 2016 Christoph Reiter, 2019 Dan Yeaw
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
"""This file gets edited at build time to add build specific data"""
BUILD_TYPE = u"default"
"""Either 'windows', 'windows-portable', 'osx-gaphor', or 'default'"""
BUILD_INFO = u""
"""Additional build info like git revision etc"""
BUILD_VERSION = 0
"""1.2.3 with a BUILD_VERSION of 1 results in 1.2.3.1"""

44
win-installer/build.sh Normal file
View File

@ -0,0 +1,44 @@
#!/usr/bin/env bash
# Copyright 2016 Christoph Reiter, 2019 Dan Yeaw
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
DIR="$( cd "$( dirname "$0" )" && pwd )"
source "$DIR"/_base.sh
function main {
local GIT_TAG=${1:-"master"}
if [[ -d "${BUILD_ROOT}" ]]; then
echo "Removing ${BUILD_ROOT}"
rm -rf "${BUILD_ROOT}"
fi
# started from the wrong env -> switch
if [ $(echo "$MSYSTEM" | tr '[A-Z]' '[a-z]') != "$MINGW" ]; then
"/${MINGW}.exe" "$0"
exit $?
fi
echo "install pre-dependencies"
install_pre_deps
echo "create root"
create_root
echo "install dependencies"
install_deps
echo "cleanup before installing gaphor"
cleanup_before
echo "install gaphor"
install_gaphor "$GIT_TAG"
echo "cleanup"
cleanup_after
echo "build installer"
build_installer
echo "build portable installer"
build_portable_installer
}
main "$@";

View File

@ -0,0 +1,17 @@
===============
Gaphor Portable
===============
Content
-------
* 'config' contains all user configuration
* 'data' contains the program
How to update to a newer version?
---------------------------------
1) Download and extract the new version
2) Replace the 'config' folder in the new version with the 'config' folder
of the older version.

View File

@ -0,0 +1,5 @@
#!/bin/bash
set -e
../_build_root/mingw64/bin/magick convert ../../gaphor/ui/pixmaps/gaphor-48x48.png gaphor2.ico

View File

@ -0,0 +1,232 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright 2016 Christoph Reiter, 2019 Dan Yeaw
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
"""Creates simple Python .exe launchers for gui and cli apps
./create-launcher.py "3.8.0" <target-dir>
"""
import os
import re
import sys
import subprocess
import shlex
import tempfile
import shutil
import struct
def build_resource(rc_path, out_path):
"""Raises subprocess.CalledProcessError"""
def is_64bit():
return struct.calcsize("P") == 8
subprocess.check_call(
[
"windres",
"-O",
"coff",
"-F",
"pe-x86-64" if is_64bit() else "pe-i386",
rc_path,
"-o",
out_path,
]
)
def get_build_args():
python_name = os.path.splitext(os.path.basename(sys.executable))[0]
python_config = os.path.join(
os.path.dirname(sys.executable), python_name + "-config"
)
cflags = subprocess.check_output(["sh", python_config, "--cflags"]).strip()
libs = subprocess.check_output(["sh", python_config, "--libs"]).strip()
cflags = os.fsdecode(cflags)
libs = os.fsdecode(libs)
return shlex.split(cflags) + shlex.split(libs)
def build_exe(source_path, resource_path, is_gui, out_path):
args = ["gcc", "-s"]
if is_gui:
args.append("-mwindows")
args.append("-municode")
args.extend(["-o", out_path, source_path, resource_path])
args.extend(get_build_args())
subprocess.check_call(args)
def get_launcher_code(entry_point):
module, func = entry_point.split(":", 1)
template = """\
#include "Python.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR lpCmdLine, int nCmdShow)
{
int result;
Py_NoUserSiteDirectory = 1;
Py_IgnoreEnvironmentFlag = 1;
Py_DontWriteBytecodeFlag = 1;
Py_Initialize();
PySys_SetArgvEx(__argc, __wargv, 0);
result = PyRun_SimpleString("%s");
Py_Finalize();
return result;
}
"""
launch_code = "import sys; from %s import %s; sys.exit(%s())" % (module, func, func)
return template % launch_code
def get_resouce_code(
filename,
file_version,
file_desc,
icon_path,
product_name,
product_version,
company_name,
):
template = """\
1 ICON "%(icon_path)s"
1 VERSIONINFO
FILEVERSION %(file_version_list)s
PRODUCTVERSION %(product_version_list)s
FILEOS 0x4
FILETYPE 0x1
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "%(company_name)s"
VALUE "FileDescription", "%(file_desc)s"
VALUE "FileVersion", "%(file_version)s"
VALUE "InternalName", "%(internal_name)s"
VALUE "OriginalFilename", "%(filename)s"
VALUE "ProductName", "%(product_name)s"
VALUE "ProductVersion", "%(product_version)s"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END
"""
def to_ver_list(v):
v = re.sub(r"rc\d", "", v)
return ",".join(map(str, (list(map(int, v.split("."))) + [0] * 4)[:4]))
file_version_list = to_ver_list(file_version)
product_version_list = to_ver_list(product_version)
return template % {
"icon_path": icon_path,
"file_version_list": file_version_list,
"product_version_list": product_version_list,
"file_version": file_version,
"product_version": product_version,
"company_name": company_name,
"filename": filename,
"internal_name": os.path.splitext(filename)[0],
"product_name": product_name,
"file_desc": file_desc,
}
def build_launcher(
out_path,
icon_path,
file_desc,
product_name,
product_version,
company_name,
entry_point,
is_gui,
):
src_ico = os.path.abspath(icon_path)
target = os.path.abspath(out_path)
file_version = product_version
dir_ = os.getcwd()
temp = tempfile.mkdtemp()
try:
os.chdir(temp)
with open("launcher.c", "w") as h:
h.write(get_launcher_code(entry_point))
shutil.copyfile(src_ico, "launcher.ico")
with open("launcher.rc", "w") as h:
h.write(
get_resouce_code(
os.path.basename(target),
file_version,
file_desc,
"launcher.ico",
product_name,
product_version,
company_name,
)
)
build_resource("launcher.rc", "launcher.res")
build_exe("launcher.c", "launcher.res", is_gui, target)
finally:
os.chdir(dir_)
shutil.rmtree(temp)
def main():
argv = sys.argv
version = argv[1]
target = argv[2]
company_name = "Gaphor Community"
misc = os.path.dirname(os.path.realpath(__file__))
build_launcher(
os.path.join(target, "gaphor.exe"),
os.path.join(misc, "gaphor.ico"),
"Gaphor",
"Gaphor",
version,
company_name,
"gaphor:main",
True,
)
build_launcher(
os.path.join(target, "gaphor-cmd.exe"),
os.path.join(misc, "gaphor.ico"),
"Gaphor",
"Gaphor",
version,
company_name,
"gaphor:main",
False,
)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,143 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright 2016,2017 Christoph Reiter
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
"""
Deletes unneeded DLLs and checks DLL dependencies.
Execute with the build python, will figure out the rest.
"""
import subprocess
import os
import sys
from multiprocessing import Process, Queue
import gi
gi.require_version("GIRepository", "2.0")
from gi.repository import GIRepository
def _get_shared_libraries(q, namespace, version):
repo = GIRepository.Repository()
repo.require(namespace, version, 0)
lib = repo.get_shared_library(namespace)
q.put(lib)
def get_shared_libraries(namespace, version):
# we have to start a new process because multiple versions can't be loaded
# in the same process
q = Queue()
p = Process(target=_get_shared_libraries, args=(q, namespace, version))
p.start()
result = q.get()
p.join()
return result
def get_required_by_typelibs():
deps = set()
repo = GIRepository.Repository()
for tl in os.listdir(repo.get_search_path()[0]):
namespace, version = os.path.splitext(tl)[0].split("-", 1)
lib = get_shared_libraries(namespace, version)
if lib:
libs = lib.lower().split(",")
else:
libs = []
for lib in libs:
deps.add((namespace, version, lib))
return deps
def get_dependencies(filename):
deps = []
try:
data = subprocess.check_output(
["objdump", "-p", filename], stderr=subprocess.STDOUT
)
except subprocess.CalledProcessError:
# can happen with wrong arch binaries
return []
data = data.decode("utf-8")
for line in data.splitlines():
line = line.strip()
if line.startswith("DLL Name:"):
deps.append(line.split(":", 1)[-1].strip().lower())
return deps
def find_lib(root, name):
system_search_path = os.path.join("C:", os.sep, "Windows", "System32")
if get_lib_path(root, name):
return True
elif os.path.exists(os.path.join(system_search_path, name)):
return True
elif name in ["gdiplus.dll"]:
return True
elif name.startswith("msvcr"):
return True
return False
def get_lib_path(root, name):
search_path = os.path.join(root, "bin")
if os.path.exists(os.path.join(search_path, name)):
return os.path.join(search_path, name)
def get_things_to_delete(root):
extensions = [".exe", ".pyd", ".dll"]
all_libs = set()
needed = set()
for base, dirs, files in os.walk(root):
for f in files:
lib = f.lower()
path = os.path.join(base, f)
ext_lower = os.path.splitext(f)[-1].lower()
if ext_lower in extensions:
if ext_lower == ".exe":
# we use .exe as dependency root
needed.add(lib)
all_libs.add(f.lower())
for lib in get_dependencies(path):
all_libs.add(lib)
needed.add(lib)
if not find_lib(root, lib):
print("MISSING:", path, lib)
for namespace, version, lib in get_required_by_typelibs():
all_libs.add(lib)
needed.add(lib)
if not find_lib(root, lib):
print("MISSING:", namespace, version, lib)
to_delete = []
for not_depended_on in all_libs - needed:
path = get_lib_path(root, not_depended_on)
if path:
to_delete.append(path)
return to_delete
def main(argv):
libs = get_things_to_delete(sys.prefix)
if "--delete" in argv[1:]:
while libs:
for l in libs:
print("DELETE:", l)
os.unlink(l)
libs = get_things_to_delete(sys.prefix)
if __name__ == "__main__":
main(sys.argv)

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

View File

@ -0,0 +1,185 @@
; Copyright 2016 Christoph Reiter, 2019 Dan Yeaw
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version.
Unicode true
!define NAME "Gaphor"
!define ID "gaphor"
!define DESC "Modeling Tool"
!define WEBSITE "https://gaphor.readthedocs.io"
!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}"
!define INSTDIR_KEY "Software\${NAME}"
!define INSTDIR_VALUENAME "InstDir"
!define MUI_CUSTOMFUNCTION_GUIINIT custom_gui_init
!include "MUI2.nsh"
!include "FileFunc.nsh"
Name "${NAME} (${VERSION})"
OutFile "gaphor-LATEST.exe"
SetCompressor /SOLID /FINAL lzma
SetCompressorDictSize 32
InstallDir "$PROGRAMFILES\${NAME}"
RequestExecutionLevel admin
Var INST_BIN
Var UNINST_BIN
!define MUI_ABORTWARNING
!define MUI_ICON "..\gaphor.ico"
!insertmacro MUI_PAGE_LICENSE "..\gaphor\LICENSE.txt"
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
!insertmacro MUI_LANGUAGE "Catalan"
!insertmacro MUI_LANGUAGE "Dutch"
!insertmacro MUI_LANGUAGE "French"
!insertmacro MUI_LANGUAGE "PortugueseBR"
!insertmacro MUI_LANGUAGE "Russian"
!insertmacro MUI_LANGUAGE "Spanish"
!insertmacro MUI_LANGUAGE "Swedish"
Section "Install"
SetShellVarContext all
; Use this to make things faster for testing installer changes
;~ SetOutPath "$INSTDIR\bin"
;~ File /r "mingw32\bin\*.exe"
SetOutPath "$INSTDIR"
File /r "*.*"
StrCpy $INST_BIN "$INSTDIR\bin\gaphor.exe"
StrCpy $UNINST_BIN "$INSTDIR\uninstall.exe"
; Store installation folder
WriteRegStr HKLM "${INSTDIR_KEY}" "${INSTDIR_VALUENAME}" $INSTDIR
; Set up an entry for the uninstaller
WriteRegStr HKLM "${UNINST_KEY}" \
"DisplayName" "${NAME} - ${DESC}"
WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$\"$INST_BIN$\""
WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" \
"$\"$UNINST_BIN$\""
WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" \
"$\"$UNINST_BIN$\" /S"
WriteRegStr HKLM "${UNINST_KEY}" "InstallLocation" "$INSTDIR"
WriteRegStr HKLM "${UNINST_KEY}" "HelpLink" "${WEBSITE}"
WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${NAME} Community"
WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${VERSION}"
WriteRegDWORD HKLM "${UNINST_KEY}" "NoModify" 0x1
WriteRegDWORD HKLM "${UNINST_KEY}" "NoRepair" 0x1
; Installation size
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
IntFmt $0 "0x%08X" $0
WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0"
; Register a default entry for file extension
WriteRegStr HKLM "Software\Classes\${NAME}.ModelFile\open\command" "" "$\"$INST_BIN$\""
WriteRegStr HKLM "Software\Classes\${NAME}.ModelFile\DefaultIcon" "" "$\"$INST_BIN$\""
; Register supported file extension
WriteRegStr HKLM "Software\Classes\.${ID}" ".gaphor" "${NAME}.ModelFile"
; Add application entry
WriteRegStr HKLM "Software\${NAME}\${ID}\Capabilities" "ApplicationDescription" "${DESC}"
WriteRegStr HKLM "Software\${NAME}\${ID}\Capabilities" "ApplicationName" "${NAME}"
; Register application entry
WriteRegStr HKLM "Software\RegisteredApplications" "${NAME}" "Software\${NAME}\${ID}\Capabilities"
; Register app paths
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\App Paths\gaphor.exe" "" "$INST_BIN"
; Create uninstaller
WriteUninstaller "$UNINST_BIN"
; Create start menu shortcuts
CreateDirectory "$SMPROGRAMS\${NAME}"
CreateShortCut "$SMPROGRAMS\${NAME}\${NAME}.lnk" "$INST_BIN"
SectionEnd
Function custom_gui_init
BringToFront
; Read the install dir and set it
Var /GLOBAL instdir_temp
Var /GLOBAL uninst_bin_temp
SetRegView 32
ReadRegStr $instdir_temp HKLM "${INSTDIR_KEY}" "${INSTDIR_VALUENAME}"
SetRegView lastused
StrCmp $instdir_temp "" skip 0
StrCpy $INSTDIR $instdir_temp
skip:
SetRegView 64
ReadRegStr $instdir_temp HKLM "${INSTDIR_KEY}" "${INSTDIR_VALUENAME}"
SetRegView lastused
StrCmp $instdir_temp "" skip2 0
StrCpy $INSTDIR $instdir_temp
skip2:
StrCpy $uninst_bin_temp "$INSTDIR\uninstall.exe"
; try to un-install existing installations first
IfFileExists "$INSTDIR" do_uninst do_continue
do_uninst:
; instdir exists
IfFileExists "$uninst_bin_temp" exec_uninst rm_instdir
exec_uninst:
; uninstall.exe exists, execute it and
; if it returns success proceede, otherwise abort the
; installer (uninstall aborted by user for example)
ExecWait '"$uninst_bin_temp" _?=$INSTDIR' $R1
; uninstall suceeded, since the uninstall.exe is still there
; goto rm_instdir as well
StrCmp $R1 0 rm_instdir
; uninstall failed
Abort
rm_instdir:
; either the uninstaller was sucessfull or
; the uninstaller.exe wasn't found
RMDir /r "$INSTDIR"
do_continue:
; the instdir shouldn't exist from here on
BringToFront
FunctionEnd
Section "Uninstall"
SetShellVarContext all
SetAutoClose true
; Remove start menu entries
Delete "$SMPROGRAMS\${NAME}\${NAME}.lnk"
RMDir "$SMPROGRAMS\${NAME}"
; Remove application registration and file assocs
DeleteRegKey HKLM "Software\Classes\${NAME}.ModelFile"
DeleteRegKey HKLM "Software\.${ID}"
DeleteRegKey HKLM "Software\${NAME}"
DeleteRegValue HKLM "Software\RegisteredApplications" "${NAME}"
; Remove app paths
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\App Paths\gaphor.exe"
; Delete installation related keys
DeleteRegKey HKLM "${UNINST_KEY}"
DeleteRegKey HKLM "${INSTDIR_KEY}"
; Delete files
RMDir /r "$INSTDIR"
SectionEnd

44
win-installer/rebuild.sh Normal file
View File

@ -0,0 +1,44 @@
#!/usr/bin/env bash
# Copyright 2016 Christoph Reiter, 2019 Dan Yeaw
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
DIR="$( cd "$( dirname "$0" )" && pwd )"
source "$DIR"/_base.sh
set_build_root "${DIR}/_rebuild_root"
function main {
local INSTALLER_PATH=${1}
local GIT_TAG=${2:-"master"}
[[ -d "${BUILD_ROOT}" ]] && (echo "${BUILD_ROOT} already exists"; exit 1)
# started from the wrong env -> switch
if [ $(echo "$MSYSTEM" | tr '[A-Z]' '[a-z]') != "$MINGW" ]; then
"/${MINGW}.exe" "$0"
exit $?
fi
echo "install pre-dependencies"
install_pre_deps
echo "create root"
create_root
echo "extract installer"
extract_installer "$INSTALLER_PATH"
echo "cleanup before installing gaphor"
cleanup_before
echo "install gaphor"
install_gaphor "$GIT_TAG"
echo "cleanup"
cleanup_after
echo "build installer"
build_installer
echo "build portable installer"
build_portable_installer
}
main "$@";