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
10 # TODO refactor: make class BuilderTools
13 def exec_cmd(cmd
, check
=True):
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
=check
)
18 return proc
.stdout
.strip() + proc
.stderr
.strip()
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}')
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
34 for __branch
in branches
:
36 print(f
'try: {root}' + 'assets/build_version.txt')
37 with
open(root
+ 'assets/build_version.txt', encoding
='utf8') as fver
:
39 print(f
'ver: {__ver}')
40 # if __branch in __ver:
41 b2c
= {'master': 'a', 'rc': 'r', 'stable': '.'}
42 if __ver
[1] == b2c
[__branch
]:
44 except FileNotFoundError
:
45 print(f
'file not found: {root}' + 'assets/build_version.txt')
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"):
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
61 print(f
'try: {root}' + 'assets/build_version.txt')
62 with
open(root
+ 'assets/build_version.txt', encoding
='utf8') as fver
:
64 print(f
'ver: {__ver}')
65 return __ver
.split('-')[1]
66 except FileNotFoundError
:
67 print(f
'file not found: {root}' + 'assets/build_version.txt')
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
77 if _branch() == 'stable':
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
)
85 # try: we want an error!
86 pref
= {'master': 'a', 'rc': 'rc', '': 'runtime'}[_branch()]
89 ret_ver
= f
'0{pref}{day}'
91 bld_ver
= pref
+ '-' + _commit()
93 with
open(root
+ 'assets/build_version.txt', 'w', encoding
='utf8') as fver
:
96 print("we can't write inside flatpaks, but we don't need it")
100 class FindFileNamesInfo
:
102 def __init__(self
, extensions
, excluding_directories
=None,
103 excluding_files_ending_with
=None, root_path
='.'):
104 self
.extensions
= extensions
105 self
.excluding_directories
= excluding_directories
106 self
.excluding_files_ending_with
= excluding_files_ending_with
107 self
.root_path
= root_path
110 def find_file_names(find_info
):
111 #TODO avoid FindFileNamesInfo, write multiple functions with different
112 # behaviors: this is a function which does more than one thing
113 _extensions
= find_info
.extensions
114 excl_dirs
= find_info
.excluding_directories
115 excl_ends_with
= find_info
.excluding_files_ending_with
116 root_path
= find_info
.root_path
117 return [join(root
, fname
)
118 for root
, _
, fnames
in walk(root_path
)
119 for fname
in __files_ext(fnames
, _extensions
)
120 if not any(e_d
in root
.split('/') for e_d
in excl_dirs
or []) and
121 not any(fname
.endswith(e_e
) for e_e
in excl_ends_with
or [])]
124 def __files_ext(fnames
, _extensions
):
125 return [fname
for fname
in fnames
126 if any(fname
.endswith('.' + ext
) for ext
in _extensions
)]
129 def __to_be_built_single(src
, tgt
):
130 if getmtime(tgt
) > getmtime(src
):
131 print(f
'{tgt} is newer than {src}: do not build')
133 with
open(src
, 'rb') as fsrc
:
134 src_content
= fsrc
.read()
135 with
open(tgt
, 'rb') as ftgt
:
136 tgt_content
= ftgt
.read()
137 hash_src
= md5(src_content
).hexdigest()
138 hash_tgt
= md5(tgt_content
).hexdigest()
141 if exists('hash_cache.txt'):
142 with
open('hash_cache.txt', encoding
='utf8') as fhash
:
143 lines
= fhash
.readlines()
145 line_spl
= line
.split()
147 fname
= ' '.join(line_spl
[:-1])
149 if src
in cache
and tgt
in cache
:
150 if hash_src
== cache
[src
] and \
151 hash_tgt
== cache
[tgt
]:
152 print(f
'{tgt} and {src} are in the cache: do not build')
154 print(f
'{src} and {tgt} are not up-to-date: building...')
158 def to_be_built(tgt
, srcs
):
159 '''Should tgt be built (i.e. is it older?) from sources srcs?'''
161 print(tgt
+ ' does not exist: building...')
163 return any(__to_be_built_single(src
, tgt
) for src
in srcs
)
167 '''Context manager for working inside a directory.'''
169 def __init__(self
, dir_
):
171 self
.old_dir
= getcwd()
176 def __exit__(self
, exc_type
, exc_val
, exc_tb
):
180 # bld_dpath = 'build/'
183 # win_fpath = '{dst_dir}{appname}-' + f'{branch}-windows.exe'
184 # osx_fpath = '{dst_dir}{appname}-%s-osx.zip' % branch
185 # flatpak_fpath = '{dst_dir}{appname}-%s-flatpak' % branch
186 # appimage_fpath = '{dst_dir}{appname}-' + f'{branch}-appimage'
187 # docs_fpath = '{dst_dir}{appname}-%s-docs.tar.gz' % branch