ya2 · news · projects · code · about

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