Allow generating the spec file from rust project checkout
This adds the possibility to generate the spec file from a rust project checkout, by specifying either the toml file or just the directory name, without having a crate at all. This is nice when developing local projects and tweaking the metadata. The expected way to use this is 'rust2rpm .../project/', look at the generated spec file, do fixes to source, regenerate spec file, etc. $ rust2rpm -t fedora --stdout . (when testing) or $ rust2rpm -t fedora /path/to/project (in the dist-git directory) Only args that contain "/" are considered local arguments. An special exception is made for "." and "..", since that's likely to be a common use case and cannot be mistaken for a remote crate name. When --patch is used, the filename is changed from name-version-fix-metadata.diff to name-fix-metadata.diff. This seems more useful, because after the crate version is updated, the patch file would either stay the same or would just need to be rebased, and it is not tied to the crate version.
This commit is contained in:
parent
b5647abe0f
commit
2233404f98
1 changed files with 70 additions and 43 deletions
|
@ -1,5 +1,6 @@
|
||||||
import argparse
|
import argparse
|
||||||
import configparser
|
import configparser
|
||||||
|
import contextlib
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
import difflib
|
import difflib
|
||||||
import itertools
|
import itertools
|
||||||
|
@ -81,6 +82,16 @@ def file_mtime(path):
|
||||||
t = datetime.fromtimestamp(os.stat(path).st_mtime, timezone.utc)
|
t = datetime.fromtimestamp(os.stat(path).st_mtime, timezone.utc)
|
||||||
return t.astimezone().isoformat()
|
return t.astimezone().isoformat()
|
||||||
|
|
||||||
|
def local_toml(toml, version):
|
||||||
|
if os.path.isdir(toml):
|
||||||
|
toml = os.path.join(toml, 'Cargo.toml')
|
||||||
|
|
||||||
|
return toml, None, version
|
||||||
|
|
||||||
|
def local_crate(crate, version):
|
||||||
|
cratename, version = os.path.basename(crate)[:-6].rsplit('-', 1)
|
||||||
|
return crate, cratename, version
|
||||||
|
|
||||||
def download(crate, version):
|
def download(crate, version):
|
||||||
if version is None:
|
if version is None:
|
||||||
# Now we need to get latest version
|
# Now we need to get latest version
|
||||||
|
@ -105,36 +116,8 @@ def download(crate, version):
|
||||||
f.write(chunk)
|
f.write(chunk)
|
||||||
return cratef, crate, version
|
return cratef, crate, version
|
||||||
|
|
||||||
def local(crate, version):
|
@contextlib.contextmanager
|
||||||
if version is not None:
|
def toml_from_crate(cratef, crate, version):
|
||||||
raise Exception("Don't specify version when using local crates!")
|
|
||||||
assert os.path.isfile(crate)
|
|
||||||
assert crate.endswith('.crate')
|
|
||||||
cratename,version = os.path.basename(crate)[:-6].rsplit('-', 1)
|
|
||||||
cratef = crate
|
|
||||||
return cratef, cratename, version
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("-", "--stdout", action="store_true",
|
|
||||||
help="Print spec and patches into stdout")
|
|
||||||
parser.add_argument("-t", "--target", action="store",
|
|
||||||
choices=("plain", "fedora", "mageia", "opensuse"), default=get_default_target(),
|
|
||||||
help="Distribution target")
|
|
||||||
parser.add_argument("-p", "--patch", action="store_true",
|
|
||||||
help="Do initial patching of Cargo.toml")
|
|
||||||
parser.add_argument("crate", help="crates.io name")
|
|
||||||
parser.add_argument("version", nargs="?", help="crates.io version")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if args.patch:
|
|
||||||
editor = detect_editor()
|
|
||||||
|
|
||||||
if args.crate.endswith('.crate') and os.path.isfile(args.crate):
|
|
||||||
cratef,crate,version = local(args.crate, args.version)
|
|
||||||
else:
|
|
||||||
cratef,crate,version = download(args.crate, args.version)
|
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory() as tmpdir:
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
target_dir = "{}/".format(tmpdir)
|
target_dir = "{}/".format(tmpdir)
|
||||||
with tarfile.open(cratef, "r") as archive:
|
with tarfile.open(cratef, "r") as archive:
|
||||||
|
@ -144,26 +127,70 @@ def main():
|
||||||
archive.extractall(target_dir)
|
archive.extractall(target_dir)
|
||||||
toml_relpath = "{}-{}/Cargo.toml".format(crate, version)
|
toml_relpath = "{}-{}/Cargo.toml".format(crate, version)
|
||||||
toml = "{}/{}".format(tmpdir, toml_relpath)
|
toml = "{}/{}".format(tmpdir, toml_relpath)
|
||||||
assert os.path.isfile(toml)
|
if not os.path.isfile(toml):
|
||||||
|
raise IOError('crate does not contain Cargo.toml file')
|
||||||
|
yield toml
|
||||||
|
|
||||||
|
def make_patch(toml, enabled=True):
|
||||||
|
if not enabled:
|
||||||
|
return []
|
||||||
|
|
||||||
|
editor = detect_editor()
|
||||||
|
|
||||||
if args.patch:
|
|
||||||
mtime_before = file_mtime(toml)
|
mtime_before = file_mtime(toml)
|
||||||
with open(toml, "r") as fobj:
|
toml_before = open(toml).readlines()
|
||||||
toml_before = fobj.readlines()
|
|
||||||
subprocess.check_call([editor, toml])
|
subprocess.check_call([editor, toml])
|
||||||
mtime_after = file_mtime(toml)
|
mtime_after = file_mtime(toml)
|
||||||
with open(toml, "r") as fobj:
|
toml_after = open(toml).readlines()
|
||||||
toml_after = fobj.readlines()
|
toml_relpath = '/'.join(toml.split('/')[-2:])
|
||||||
diff = list(difflib.unified_diff(toml_before, toml_after,
|
diff = list(difflib.unified_diff(toml_before, toml_after,
|
||||||
fromfile=toml_relpath, tofile=toml_relpath,
|
fromfile=toml_relpath, tofile=toml_relpath,
|
||||||
fromfiledate=mtime_before, tofiledate=mtime_after))
|
fromfiledate=mtime_before, tofiledate=mtime_after))
|
||||||
|
return diff
|
||||||
|
|
||||||
|
def _is_path(path):
|
||||||
|
return '/' in path or path in {'.', '..'}
|
||||||
|
|
||||||
|
def make_diff_metadata(crate, version, patch=False):
|
||||||
|
if _is_path(crate):
|
||||||
|
# Only things that look like a paths are considered local arguments
|
||||||
|
if crate.endswith('.crate'):
|
||||||
|
cratef, crate, version = local_crate(crate, version)
|
||||||
|
else:
|
||||||
|
toml, crate, version = local_toml(crate, version)
|
||||||
|
diff = make_patch(toml, enabled=patch)
|
||||||
metadata = Metadata.from_file(toml)
|
metadata = Metadata.from_file(toml)
|
||||||
|
return metadata.name, diff, metadata
|
||||||
|
else:
|
||||||
|
cratef, crate, version = download(crate, version)
|
||||||
|
|
||||||
|
with toml_from_crate(cratef, crate, version) as toml:
|
||||||
|
diff = make_patch(toml, enabled=patch)
|
||||||
|
metadata = Metadata.from_file(toml)
|
||||||
|
return crate, diff, metadata
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser('rust2rpm',
|
||||||
|
formatter_class=argparse.RawTextHelpFormatter)
|
||||||
|
parser.add_argument("-", "--stdout", action="store_true",
|
||||||
|
help="Print spec and patches into stdout")
|
||||||
|
parser.add_argument("-t", "--target", action="store",
|
||||||
|
choices=("plain", "fedora", "mageia", "opensuse"), default=get_default_target(),
|
||||||
|
help="Distribution target")
|
||||||
|
parser.add_argument("-p", "--patch", action="store_true",
|
||||||
|
help="Do initial patching of Cargo.toml")
|
||||||
|
parser.add_argument("crate", help="crates.io name\n"
|
||||||
|
"path/to/local.crate\n"
|
||||||
|
"path/to/project/")
|
||||||
|
parser.add_argument("version", nargs="?", help="crates.io version")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
crate, diff, metadata = make_diff_metadata(args.crate, args.version, patch=args.patch)
|
||||||
|
|
||||||
template = JINJA_ENV.get_template("main.spec")
|
template = JINJA_ENV.get_template("main.spec")
|
||||||
|
|
||||||
if args.patch and len(diff) > 0:
|
if args.patch and len(diff) > 0:
|
||||||
patch_file = "{}-{}-fix-metadata.diff".format(crate, version)
|
patch_file = "{}-fix-metadata.diff".format(crate)
|
||||||
else:
|
else:
|
||||||
patch_file = None
|
patch_file = None
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue