ya2 · news · projects · code · about

fixed version
[pmachines.git] / lib / build / build.py
1 '''Tools for making the builds.'''
2 from os import walk, chdir, getcwd
3 from os.path import join, getsize, exists, dirname, getmtime, sep
4 from subprocess import Popen, PIPE, run
5 from logging import debug
6 from time import strftime
7 from pathlib import Path
8 from hashlib import md5
9
10
11 #TODO refactor: make class BuilderTools
12
13
14 def exec_cmd(cmd):
15 '''Synchronously executes a command and returns its output.'''
16 #ret = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True).communicate()
17 #return ret[0].decode('utf-8').strip()
18 proc = run(cmd, shell=True, stdout=PIPE, stderr=PIPE, universal_newlines=True)
19 return proc.stdout.strip() + proc.stderr.strip()
20
21
22 def _branch():
23 '''Returns the current branch.'''
24 git_branch = exec_cmd('git symbolic-ref HEAD').split('/')[-1].strip()
25 print('git_branch result: %s' % git_branch)
26 branches = ['master', 'rc', 'stable']
27 if git_branch in branches:
28 print('git_branch: %s' % git_branch)
29 return git_branch
30 root = str(Path(dirname(dirname(__file__))).parent) + '/'
31 if 'itch' in __file__.split(sep):
32 root = str(Path(dirname(__file__))) + '/'
33 if __file__ == '/app/bin/pmachines': # flatpak
34 root = '/app/bin/'
35 for branch in branches:
36 try:
37 print('try: %s' % root + 'assets/bld_version.txt')
38 with open(root + 'assets/bld_version.txt') as fver:
39 ver = fver.read()
40 print('ver: %s' % ver)
41 #if branch in ver:
42 b2c = {'master': 'a', 'rc': 'r', 'stable': '.'}
43 if ver[1] == b2c[branch]:
44 return branch
45 except FileNotFoundError:
46 print('file not found: %s' % root + 'assets/bld_version.txt')
47
48
49 def _commit():
50 '''Returns the current branch.'''
51 git_commit = exec_cmd('git rev-parse HEAD')[:7]
52 print('git_commit result: %s' % git_commit)
53 if not git_commit.startswith("Can't r"):
54 return git_commit
55 root = str(Path(dirname(dirname(__file__))).parent) + '/'
56 if 'itch' in __file__.split(sep):
57 root = str(Path(dirname(__file__))) + '/'
58 if __file__ == '/app/bin/pmachines': # flatpak
59 root = '/app/bin/'
60 try:
61 print('try: %s' % root + 'assets/bld_version.txt')
62 with open(root + 'assets/bld_version.txt') as fver:
63 ver = fver.read()
64 print('ver: %s' % ver)
65 return ver.split('-')[1]
66 except FileNotFoundError:
67 print('file not found: %s' % root + 'assets/bld_version.txt')
68
69
70 def _version():
71 '''Computes the version of the current build.'''
72 day = strftime('%y%m%d')
73 root = str(Path(dirname(dirname(__file__))).parent) + '/'
74 if __file__ == '/app/bin/pmachines': # flatpak
75 root = '/app/bin/'
76 if _branch() == 'stable':
77 pref, _ver = '', ''
78 if exists(root + 'assets/version.txt'):
79 with open(root + 'assets/version.txt') as fver:
80 pref = fver.read().strip() + '-' # + _branch() + '-'
81 _ver = fver.read().strip()
82 ret_ver = _ver or ('0.' + day)
83 else:
84 #try: we want an error!
85 pref = {'master': 'a', 'rc': 'rc', '': 'runtime'}[_branch()]
86 #except KeyError:
87 # pref = 'notfound'
88 ret_ver = '0%s%s' % (pref, day)
89 pref = ret_ver
90 bld_ver = pref + '-' + _commit()
91 try:
92 with open(root + 'assets/bld_version.txt', 'w') as fver:
93 fver.write(bld_ver)
94 except OSError:
95 print("we can't write inside flatpaks, but we don't need it")
96 return ret_ver
97
98
99 def files(_extensions, excl_dirs=None, excl_ends_with=None, root_path='.'):
100 '''Retrieves filenames in root_path with _extensions, with filters.'''
101 return [join(root, fname)
102 for root, _, fnames in walk(root_path)
103 for fname in __files_ext(fnames, _extensions)
104 if not any(e_d in root.split('/') for e_d in excl_dirs or []) and
105 not any(fname.endswith(e_e) for e_e in excl_ends_with or [])]
106
107
108 def __files_ext(fnames, _extensions):
109 return [fname for fname in fnames
110 if any(fname.endswith('.' + ext) for ext in _extensions)]
111
112
113 def __to_be_built_single(src, tgt):
114 if getmtime(tgt) > getmtime(src):
115 print('%s is newer than %s: do not build' % (tgt, src))
116 return False
117 with open(src, 'rb') as f:
118 src_content = f.read()
119 with open(tgt, 'rb') as f:
120 tgt_content = f.read()
121 hash_src = md5(src_content).hexdigest()
122 hash_tgt = md5(tgt_content).hexdigest()
123 cache = {}
124 lines = []
125 if exists('hash_cache.txt'):
126 with open('hash_cache.txt') as f:
127 lines = f.readlines()
128 for line in lines:
129 line_spl = line.split()
130 hash = line_spl[-1]
131 fname = ' '.join(line_spl[:-1])
132 cache[fname] = hash
133 if src in cache and tgt in cache:
134 if hash_src == cache[src] and \
135 hash_tgt == cache[tgt]:
136 print('%s and %s are in the cache: do not build' % (tgt, src))
137 return False
138 print('%s and %s are not up-to-date: building...' % (src, tgt))
139 return True
140
141
142 def to_be_built(tgt, srcs):
143 '''Should tgt be built (i.e. is it older?) from sources srcs?'''
144 if not exists(tgt):
145 print(tgt + ' does not exist: building...')
146 return True
147 return any(__to_be_built_single(src, tgt) for src in srcs)
148
149
150 class InsideDir:
151 '''Context manager for working inside a directory.'''
152
153 def __init__(self, dir_):
154 self.dir = dir_
155 self.old_dir = getcwd()
156
157 def __enter__(self):
158 chdir(self.dir)
159
160 def __exit__(self, exc_type, exc_val, exc_tb):
161 chdir(self.old_dir)
162
163
164 bld_dpath = 'build/'
165 branch = _branch()
166 ver = _version()
167 win_fpath = '{dst_dir}{appname}-%s-windows.exe' % branch
168 #osx_fpath = '{dst_dir}{appname}-%s-osx.zip' % branch
169 #flatpak_fpath = '{dst_dir}{appname}-%s-flatpak' % branch
170 appimage_fpath = '{dst_dir}{appname}-%s-appimage' % branch
171 docs_fpath = '{dst_dir}{appname}-%s-docs.tar.gz' % branch