ya2 · news · projects · code · about

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