ya2 · news · projects · code · about

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